动态规划(5)

58 阅读1分钟

Day10 备忘录

1、931. 下降路径最小和

  • 思路:
    • 维护二维DP数组,记录每一个格子对应的最小路径。
    • dp[i][j]=Min[dp[i1][j1],dp[i1][j],dp[i1][j+1]]dp[i][j] = Min[dp[i-1][j-1],dp[i-1][j],dp[i-1][j + 1]]
    class Solution {
        public int minFallingPathSum(int[][] matrix) {
    	int rows = matrix.length;
    	int cols = matrix[0].length;
    	//表示每一层的最小路径和
    	int[][] dp = new int[rows][cols];
    	for (int i = 0; i < cols; i++) {
    		dp[0][i] = matrix[0][i];
    	}
    	for (int i = 1; i < rows; i++) {
    		for (int j = 0; j < cols; j++) {
    			int temp = dp[i - 1][j];
    			if (j - 1 >= 0){
    				temp = Math.min(dp[i - 1][j - 1],temp);
    			}
    			if (j + 1 < cols){
    				temp = Math.min(dp[i - 1][j + 1],temp);
    			}
    			dp[i][j] = temp + matrix[i][j];
    		}
    	}
    	int ans = dp[rows - 1][0];
    	for (int i = 1; i < cols; i++) {
    		ans = Math.min(dp[rows - 1][i],ans);
    	}
    	return ans;
        }
    }
    
  • 数组空间优化
    • 只用记录上一层的最小路径就好,可以优化成一个 rowsrows 长的一维数组
    class Solution {
        public int minFallingPathSum(int[][] matrix) {
            int rows = matrix.length;
            int cols = matrix[0].length;
            int ans = Integer.MAX_VALUE;
            //表示每一层的最小路径和
            int[] dp = new int[cols + 1];
            for (int i = 0; i < cols; i++) {
                dp[i] = matrix[0][i];
            }
            //确保
            dp[cols] = Integer.MAX_VALUE;
            for (int i = 1; i < rows; i++) {
                int temp = 0, last = Integer.MAX_VALUE;
                for (int j = 0; j < cols; j++) {
                    //保存当前dp[j]供下一次dp[j+1]求dp[j-1]
                    temp = dp[j];
                    dp[j] = Math.min(Math.min(last, dp[j]), dp[j + 1]) + matrix[i][j];
                    last = temp;
                }
            }
            for (int item : dp) {
                ans = Math.min(item, ans);
            }
            return ans;
        }
    }
    

2、53. 最大子数组和

  • 思路:
    • 动态规划。dp数组表示以i为结尾的最大子数组和
    • dp数组可以优化为常数
    class Solution {
        public int maxSubArray(int[] nums) {
    	int ans = nums[0];
    	int max = nums[0];
    	for (int i = 1; i < nums.length; i++) {
    		max = Math.max(max + nums[i],nums[i]);
    		ans = Math.max(ans,max);
    	}
    	return ans;
        }
    }
    
  • 分治
    class Solution {
        public int maxSubArray(int[] nums) {
            return getInfo(nums,0,nums.length - 1);
        }
    
        public int getAns(int[] nums, int l, int mid, int r) {
            // 一定会包含 nums[mid] 这个元素
            int sum = 0;
            int leftSum = Integer.MIN_VALUE;
            // 左半边包含 nums[mid] 元素,最多可以到什么地方
            // 走到最边界,看看最值是什么
            // 计算以 mid 结尾的最大的子数组的和
            for (int i = mid; i >= l; i--) {
                sum += nums[i];
                if (sum > leftSum) {
                    leftSum = sum;
                }
            }
            sum = 0;
            int rightSum = Integer.MIN_VALUE;
            // 右半边不包含 nums[mid] 元素,最多可以到什么地方
            // 计算以 mid+1 开始的最大的子数组的和
            for (int i = mid + 1; i <= r; i++) {
                sum += nums[i];
                if (sum > rightSum) {
                    rightSum = sum;
                }
            }
            return leftSum + rightSum;
        }
    
        public int getInfo(int[] nums, int l, int r) {
            if (l == r) {
                return nums[l];
            }
            int mid = l + (r - l) / 2;
            return Math.max(
                    getInfo(nums, l, mid),
                    Math.max(getInfo(nums, mid + 1, r),
                            getAns(nums, l, mid, r)));
        }
    }