剑指OFFER思路总结与代码分享——动态规划篇(Java实现)

剑指OFFER动态规划相关

  • 47 礼物的最大价值
  • 63 股票的最大利润
  • 42 连续子数组最大和
  • 14-I 剪绳子
  • 12 矩阵中的路径
  • 19 正则表达式匹配
  • 14-II 剪绳子 II

注:顺序是先筛选分类再按LeeCode上的通过率排的,每题最后的总结代码都是在LeeCode上跑过的,应该没啥问题。但是思路中的代码都是直接在CSDN编辑器里徒手敲的,若有笔误还烦请告知,蟹蟹~

47 礼物的最大价值

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第1张图片
做动态规划先找初始条件,再根据初始条件得到递推式,最后返回题目要求的那个值即可。
这题的初始条件是首行和首列,因为首行只能往右走,首列只能往下走,是确定好的,所以我们第一步就把首行首列算出来;然后就是找递推式了,这题很明显递推式就是你上一个或者左边一个中的最大值加上你自己的值;最后的返回值就是右下角的那个了。

class Solution {
     
    public int maxValue(int[][] grid) {
     
    	//先判空
        if(grid.length == 0){
     
            return 0;
        }
		//先把长、宽给定在这,这样后面写的时候也不会混淆
        int m = grid[0].length, n = grid.length;
		//dp数组安排上
        int[][] dp = new int[n][m];
        
        //把初始条件准备好
        dp[0][0] = grid[0][0];
        for(int i = 1; i < m; i++){
     
            dp[0][i] = dp[0][i-1] + grid[0][i]; 
        }
        for(int j = 1; j < n; j++){
     
            dp[j][0] += dp[j-1][0] + grid[j][0];
        }
		
		//开始递推
        for(int i = 1; i < m; i++){
     
            for(int j = 1; j < n; j++){
     
                dp[j][i] = Math.max(dp[j][i-1],dp[j-1][i]) + grid[j][i];
            }
        }
		
		//最后返回即可
        return dp[n-1][m-1];
        
    }
}

总结递推公式:
dp[j][i] = Math.max(dp[j][i-1],dp[j-1][i]) + grid[j][i];


63 股票的最大利润

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第2张图片
这题的特殊之处是我们要一个int来记录我们的最小值,这样之后的数据才好进行比较。
这里dp记录的是到第i天为止所能获得的最大利润,第0天当然是啥也不干,不然买多少等于亏多少。
递推关系就是比较我第i天卖出的利润高还是不管他的利润高。第i天卖出所得到的的最大利润是prices[i] - min,啥也不干那就是前一天的利润最大值dp[i-1]了。
最后返回的是最后一天的利润最大值即可。

class Solution {
     
    public int maxProfit(int[] prices) {
     
        if(prices.length == 0){
     
            return 0;
        }
        int n = prices.length;
        int[] dp = new int[n];
        //初始化
        dp[0] = 0;
        int min = prices[0];
	
		//开始递推
        for(int i = 1; i < n; i++){
     
            dp[i] = Math.max(dp[i-1], prices[i] - min);
            if(prices[i] < min){
     
                min = prices[i];
            }
        }
        
        //返回
        return dp[n-1];
    }
}

总结递推公式:
dp[i] = Math.max(dp[i-1], prices[i] - min);

42 连续子数组最大和

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第3张图片
dp记录的是以i结尾的子数组的最大和,递推要考虑的就是是否加上前面的元素。然后再将全局的最大子数组和记录下来并返回即可。

class Solution {
     
    public int maxSubArray(int[] nums) {
     
        int n = nums.length;
        if(n == 0){
     
            return 0;
        }

        int[] dp = new int[n];
        dp[0] = nums[0];
        int max = dp[0];
        for(int i = 1; i < n; i++){
     
            dp[i] = Math.max(nums[i], dp[i-1] + nums[i]);
            if(dp[i] > max){
     
                max = dp[i];
            }
        }
        return max;
    }
}

总结递推公式:
dp[i] = Math.max(nums[i], dp[i-1] + nums[i]);

14-I 剪绳子

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第4张图片
dp[i]是当绳子长度为i时的最大乘积。当i为1时,最大乘积就是1。递推公式是从1到i的一次遍历,找到当前i的最大乘积,具体计算方法为:

//dp[i]是循环到目前的最大值,然后每次按j去切看它的最大乘积是多少,是否比以往的最大值大即可
Math.max(dp[i],Math.max(j,dp[j]) * (i-j));

最后返回dp[n]即可。

class Solution {
     
    public int cuttingRope(int n) {
     
        int[] dp = new int[n + 1];
        dp[1] = 1;
        for(int i = 2; i <= n; i++){
     
            for(int j = 1; j < i; j++){
     
                dp[i] = Math.max(dp[i],Math.max(j,dp[j]) * (i-j));
            }
        }
        return dp[n];

    }
}

总结递推公式:
dp[i] = Math.max(dp[i],Math.max(j,dp[j]) * (i-j));

12 矩阵中的路径

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第5张图片
这题不是dp啊…这题是dfs…
dfs的话大概是这个板子:

boolean dfs(){
     
	剪枝操作
	终止条件
	四处递归
}

首先要把不符合的情况给减掉,就是遇到不符合要求的就return false回去;
然后就是符合条件的要return true回去;
最后是向上下左右四个方向递归,当然在递归的前后还是需要做一些操作的。
其实感觉就是很像普通递归题的思路,往四个方向做递归嘛就。

class Solution {
     
    public boolean exist(char[][] board, String word) {
     
        if(board.length == 0){
     
            return false;
        }
        char[] words =word.toCharArray();
        for(int i = 0; i < board[0].length; i++){
     
            for(int j = 0; j < board.length; j++){
     
                if(dfs(board,words,j,i,0)){
     
                    return true;
                }
            }
        }
        return false;
    }

    private boolean dfs(char[][] board, char[] word,int j, int i, int k){
     
    	//剪枝
        if(j >= board.length || j < 0 || i >= board[0].length || i < 0 || board[j][i] != word[k]){
     
            return false;
        }
        //成功返回
        if(k == word.length - 1){
     
            return true;
        }
        //递归准备
        char tmp = board[j][i];
        board[j][i] = '$';
        //四个方向递归
        boolean res = dfs(board, word, j + 1, i, k + 1) ||
            dfs(board, word, j - 1, i, k + 1) ||
            dfs(board, word, j, i + 1, k + 1) ||
            dfs(board, word, j, i - 1, k + 1);
        board[j][i] = tmp;
        return res;
    }
}

19 正则表达式匹配

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第6张图片
写了半天写不出来,还是看大佬的题解吧:传送门

14-II 剪绳子 II

剑指OFFER思路总结与代码分享——动态规划篇(Java实现)_第7张图片
找规律天秀解法:尽可能多的3相乘,逃

class Solution {
     
    public int cuttingRope(int n) {
     
        if(n <= 3){
     
            return n - 1;
        }
        long res = 1;
        while(n > 4){
     
            n -= 3;
            res = (res * 3) % 1000000007;
        }
        return (int)(res * n % 1000000007);
    }
}

你可能感兴趣的:(剑指Offer,剑指Offer,算法,动态规划)