剑指10-1 斐波那契数列
class Solution { public int fib(int n) { int a = 0,b=1,sum; for(int i=0;i<n;i++){ sum = (a+b)%1000000007; a=b; b=sum; } return a; }}
leetcode 42 接雨水
// v1.0 时间复杂度O(N^2)class Solution { public int trap(int[] height) { // 按列求,每列能接的雨水与左右两侧最高的柱子有关 int res = 0; int len = height.length; for(int i=1;i<len-1;i++){ int leftMax = 0; for(int m=0;m<i;m++){ if(height[m]>leftMax){ leftMax = height[m]; } } int rightMax = 0; for(int n=i+1;n<len;n++){ if(height[n]>rightMax){ rightMax = height[n]; } } int max = Math.min(leftMax, rightMax); if(max>height[i]){ res += max-height[i]; } } return res; }}// v2.0 动态规划class Solution { public int trap(int[] height) { // 动态规划,将左边最高的和右边最高的先求出来,不放在for循环中 int res = 0; int len = height.length; if(len<3){ return 0; } int[] left = new int[len]; int[] right = new int[len]; for(int i = 1;i<len-1;i++){ left[i] = Math.max(left[i-1],height[i-1]); } for(int i=len-2;i>=1;i--){ right[i] = Math.max(right[i+1],height[i+1]); } for(int i=1;i<len-1;i++){ int max = Math.min(left[i],right[i]); if(max>height[i]){ res+=(max-height[i]); } } return res; }}// v3.0 双指针class Solution { public int trap(int[] height) { // 双指针,用常量存储leftMax和rightMax // https://leetcode-cn.com/problems/trapping-rain-water/solution/jie-yu-shui-by-leetcode/327718 int res = 0; int len = height.length; int left = 0, right = len-1; int maxLeft = 0, maxRight = 0; while(left<=right){ if(maxLeft<maxRight){ res += Math.max(0, maxLeft-height[left]); maxLeft = Math.max(maxLeft, height[left]); left++; }else{ res +=Math.max(0, maxRight-height[right]); maxRight = Math.max(maxRight, height[right]); right--; } } return res; }}
leetcode 53 最大子序和
class Solution { public int maxSubArray(int[] nums) { // f(n) = max{f(n-1)+nums[n],nums[n]} int res = -100000; int tmp = -100000; for(int num:nums){ tmp = Math.max(tmp+num,num); res = Math.max(res, tmp); } return res; }}
leetcode 62 不同路径
class Solution { public int uniquePaths(int m, int n) { int[][] res = new int[m][n]; for(int i=0;i<m;i++){ for(int j=0;j<n;j++){ if(i==0||j==0){ res[i][j]=1; }else{ res[i][j] = res[i][j-1]+res[i-1][j]; } } } return res[m-1][n-1]; }}
leetcode 72 编辑距离
class Solution { public int minDistance(String word1, String word2) { int firLen = word1.length(); int secLen = word2.length(); int[][] matrix = new int[firLen+1][secLen+1]; for(int i=0;i<firLen+1;i++){ matrix[i][0] = i; } for(int i=0;i<secLen+1;i++){ matrix[0][i] = i; } for(int m=1;m<firLen+1;m++){ for(int n=1;n<secLen+1;n++){ if(word1.charAt(m-1)==word2.charAt(n-1)){ matrix[m][n] = matrix[m-1][n-1]; }else{ matrix[m][n] = Math.min(Math.min(matrix[m-1][n],matrix[m-1][n-1]),matrix[m][n-1])+1; } } } return matrix[firLen][secLen]; }}
leetcode 55 跳跃游戏
class Solution { public boolean canJump(int[] nums) { // 能跳到的最远位置 int jumpMax = 0; int len = nums.length; if(len==1){ return true; } for(int i=0;i<nums.length;i++){ jumpMax = Math.max(jumpMax, i+nums[i]); // 能跳到的最远处为当前位置,且当前位置跳跃距离为0时,返回false if(jumpMax==i&&nums[i]==0){ return false; } if(jumpMax>=len-1){ return true; } } return false; }}
leetcode 198 打家劫舍
class Solution { public int rob(int[] nums) { int len = nums.length; if(len==1){ return nums[0]; } // 偷窃到第i个房间时,能偷窃到的最高金额只与其前两个房间的金额有关 int first = nums[0], second = Math.max(nums[0],nums[1]); for(int i=2;i<len;i++){ int tmp = second; second = Math.max(second, first+nums[i]); first = tmp; } return second; }}
leetcode 224 最大正方形
class Solution { public int maximalSquare(char[][] matrix) { int length = matrix[0].length, height = matrix.length; int[][] dp = new int[height+1][length+1]; int maxLen = 0; for(int i=0;i<height;i++){ for(int j=0;j<length;j++){ if(matrix[i][j]=='1'){ dp[i+1][j+1] = Math.min(Math.min(dp[i][j],dp[i+1][j]),dp[i][j+1])+1; maxLen = Math.max(maxLen, dp[i+1][j+1]); } } } return maxLen*maxLen; }}
leetcode 279 完全平方数
class Solution { public int numSquares(int n) { int[] dp = new int[n+1]; int tmp = 1; for(int i=1;i<n+1;i++){ if(i == tmp*tmp){ dp[i] = 1; tmp++; continue; } dp[i] = 4; for(int j=tmp-1;j>=1;j--){ dp[i] = Math.min(dp[i],dp[j*j]+dp[i-j*j]); } } return dp[n]; }}
leetcode 300 最长递增子序列
// v1.0 动态规划 时间复杂度O(N^2)class Solution { public int lengthOfLIS(int[] nums) { int len = nums.length; if(nums.length<2){ return 1; } int res = 1; int[] dp = new int[len]; Arrays.fill(dp,1); for(int i=1;i<len;i++){ for(int j=0;j<i;j++){ if(nums[i]>nums[j]){ dp[i] = Math.max(dp[i],dp[j]+1); } } res = Math.max(res, dp[i]); } return res; }}// v2.0 二分查找class Solution { public int lengthOfLIS(int[] nums) { int res = 0; int[] dp = new int[nums.length]; for(int num:nums){ int i = 0, j=res; while(i<j){ int mid = (i+j)>>1; if(dp[mid]<num){ i = mid+1; }else{ j = mid; } } dp[j] = num; if(j==res) res ++; } return res; }}
leetcode 309 最佳买卖股票时机含冷冻期
class Solution { public int maxProfit(int[] prices) { int len = prices.length; int[][] dp = new int[3][len]; // 不手持股票 dp[0][0] = 0; // 手持股票 dp[1][0] = -prices[0]; // 冷冻期 dp[2][0] = 0; for(int i=1;i<len;i++){ // 第i天不手持股票利润最大值(第i-1天不手持股票/第i-1天冷冻期) dp[0][i] = Math.max(dp[0][i-1], dp[2][i-1]); // 第i天手持股票(第i-1天手持股票/第i-1天不手持股票且为冷冻期) dp[1][i] = Math.max(dp[1][i-1], dp[0][i-1]-prices[i]); // 第i天为冷冻期 dp[2][i] = dp[1][i-1]+prices[i]; } return Math.max(dp[0][len-1],dp[2][len-1]); }}
打家劫舍II
class Solution { public int rob(int[] nums) { int len = nums.length; if(len==1) return nums[0]; //分为两段,分别是0-n-1和1-n int a=0; int b=nums[0]; int sum=0; for(int i=1;i<len-1;i++){ sum = Math.max(b,a+nums[i]); a=b; b=sum; } int resOne = b; a=0; b=nums[1]; sum=0; for(int i=2;i<len;i++){ sum = Math.max(b,a+nums[i]); a=b; b=sum; } int resTwo = b; return Math.max(resOne,resTwo); }}
leetcode 337 打家劫舍III
class Solution { public int rob(TreeNode root) { int[] arr = robInternal(root); return Math.max(arr[0],arr[1]); } public int[] robInternal(TreeNode root){ if(root==null) return new int[2]; int[] res = new int[2];//res[0]表示偷,res[1]表示不偷 int[] left = robInternal(root.left); int[] right = robInternal(root.right); res[0] = left[1]+right[1]+root.val; res[1] = Math.max(left[0],left[1])+Math.max(right[0],right[1]); return res; }}
leetcode 121 买卖股票的最佳时机
class Solution { public int maxProfit(int[] prices) { // 动态规划 第i天利润最大值等于第i-1天利润和(第i天价格-前i-1天最低价格)中的最大值 int res = 0; int minPrice = prices[0]; for(int i=1;i<prices.length;i++){ res = Math.max(res, prices[i]-minPrice); minPrice = Math.min(minPrice,prices[i]); } return res; }}
leetcode122 买卖股票的最佳时机
class Solution { public int maxProfit(int[] prices) { int len = prices.length; if(len<2){ return 0; } int[][] dp = new int[len][2]; //0表示持有现金,1表示持有股票 dp[0][0] = 0; dp[0][1] = -prices[0]; for(int i=1;i<len;i++){ dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]); dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-prices[i]); } return dp[len-1][0]; }}
leetcode 416 分割等和子集
//0-1背包问题class Solution { public boolean canPartition(int[] nums) { int len = nums.length; int sum = 0; for(int num:nums){ sum+=num; } if((sum&1)==1){ return false; } int target = sum>>1; boolean[] dp = new boolean[target+1]; //状态压缩为一维数组 dp[0] = true; for(int i=1;i<len;i++){ //倒序更新 for(int j=target;j>=nums[i];j--){ if(dp[target]==true){ return true; } dp[j] = dp[j]||dp[j-nums[i]]; } } return dp[target]; }}
leetcode 474
class Solution { public int findMaxForm(String[] strs, int m, int n) { int len = strs.length; int[][] dp = new int[m+1][n+1]; for(int i=1;i<=len;i++){ int[] countZeroandOne = count(strs[i-1]); for(int p=m;p>=countZeroandOne[0];p--){ for(int q=n;q>=countZeroandOne[1];q--){ dp[p][q] = Math.max(dp[p][q],dp[p-countZeroandOne[0]][q-countZeroandOne[1]]+1); } } } return dp[m][n]; } public int[] count(String str){ int[] countZeroandOne = new int[2]; for(int i=0;i<str.length();i++){ countZeroandOne[str.charAt(i)-'0']++; } return countZeroandOne; }}
leetcode 152 乘积最大子数组
//imax维护当前子数组最大值,imin维护当前子数组最小值//遇到负数时,imax和imin互换class Solution { public int maxProduct(int[] nums) { int res = Integer.MIN_VALUE; int imax=1; int imin=1; for(int num:nums){ if(num<0){ int temp= imax; imax = imin; imin = temp; } imax = Math.max(imax*num,num); imin = Math.min(imin*num,num); res = Math.max(imax,res); } return res; }}
leetcode 96 不同的二叉搜索树
class Solution { public int numTrees(int n) { //设值为n时拥有的种数为G(n),当根节点为1时,左节点为null,右节点有n-1种可能性, //当根节点为2时,左节点有n-2种可能性... int[] dp = new int[n+1]; dp[0] = 1; dp[1] = 1; for(int i=2;i<n+1;i++){ for(int j=0;j<i;j++){ dp[i] += dp[j] * dp[i-1-j]; } } return dp[n]; }}
以下为背包问题类型:
leetcode 518 零钱兑换II
class Solution { public int change(int amount, int[] coins) { //完全背包问题 if(amount==0){ return 1; } int[] count = new int[amount+1]; int len = coins.length; for(int i=0;i<len;i++){ for(int j=coins[i];j<=amount;j++){ if(j==coins[i]){ count[j]=count[j]+1; continue; } count[j] = count[j]+count[j-coins[i]]; } } return count[amount]; }}
leetcode 377 组合总数IV
class Solution { public int combinationSum4(int[] nums, int target) { //完全背包问题 //dp[m] = dp[m-nums[0]]+dp[m-nums[1]]+... int[] dp = new int[target+1]; dp[0] = 1;//m=nums[i] for(int i=1;i<=target;i++){ for(int num:nums){ if(i>=num){ dp[i] += dp[i-num]; } } } return dp[target]; }}
leetcode 494 目标和
class Solution { public int findTargetSumWays(int[] nums, int target) { // sum(M)-sum(N) = target // sum(M)-sum(N)+sum(M)+sum(N) = target+sum // ==> sum(M) = (target+sum)/2 int sum = 0; for(int num:nums){ sum+=num; } if(((target+sum)&1)==1) return 0; int newTarget = (target+sum)>>1; if(newTarget<0) return 0; int[] dp = new int[newTarget+1]; dp[0] = 1; for(int i=0;i<nums.length;i++){ for(int j=newTarget;j>=nums[i];j--){ dp[j] = dp[j]+dp[j-nums[i]]; } } return dp[newTarget]; }}