动态规划刷题攻略(二)

导读:本篇文章讲解 动态规划刷题攻略(二),希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

序列型动态规划

动态规划刷题攻略(二)

265. 粉刷房子 II —- 序列型动态规划

动态规划刷题攻略(二)动态规划刷题攻略(二) 

动态规划组成部分一:确定状态

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

动态规划刷题攻略(二)动态规划刷题攻略(二)

 优化后代码:

    public int minCost(int[][] A) {
        if(A.length == 0){
            return 0;
        }
        int n = A.length;
        int k = A[0].length;
        int[][] f = new int[n + 1][k];
        int min1,min2;
        int j1 = 0,j2 = 0;//j1,j2代表最小值和次小值的下标
        for(int j = 0;j < k;j++){
            f[0][j] = 0;
        }
        for(int i = 1;i <= n;i++){
            //计算min1,min2(求最小值和次小值)
            min1 = min2 = Integer.MAX_VALUE;
            //min1 = f[i - 1][j1]
            //min2 = f[i - 1][j2]
            for(int j = 0;j < k;j++){
                if(f[i - 1][j] < min1){
                    //比原来的最小值都小,则把原来的最小值放到次小值里
                    //然后再把现在的值赋给最小
                    min2 = min1;
                    j2 = j1;
                    min1 = f[i - 1][j];
                    j1 = j;
                }else{
                    //比最小值大,比次小值小
                    if(f[i - 1][j] < min2){
                        min2 = f[i - 1][j];
                        j2 = j;
                    }
                }
            }
            for(int j = 0;j < k;j++){
                if(j != j1){
                    f[i][j] = f[i - 1][j1] + A[i - 1][j];
                }else{
                    //j == j1(正好是那个最小值)
                    f[i][j] = f[i - 1][j2] + A[i - 1][j];
                }
            }
        }
        int res = Integer.MAX_VALUE;
        for(int j = 0;j < k;j++){
            res = Math.min(res,f[n][j]);
        }
        return res;
    }

动态规划常见优化

动态规划刷题攻略(二)

动态规划刷题攻略(二) 动态规划刷题攻略(二)

剑指 Offer II 089. 房屋偷盗 —– 序列型动态规划​​​​​​

动态规划组成部分一:确定状态

动态规划刷题攻略(二)

动态规划刷题攻略(二)

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

简化:

动态规划刷题攻略(二)

动态规划组成部分三:初始条件和边界情况

动态规划刷题攻略(二)

动态规划组成部分四:计算顺序

初始化f[0]

计算f[1],f[2],….,f[n]

答案是f[n]

时间复杂度O(N),空间复杂度O(1)

    public int rob(int[] nums) {
        int n = nums.length;
        if(n == 0){
            return 0;
        }
        int[] f = new int[n + 1];
        f[0] = 0;
        f[1] = nums[0];
        for(int i = 2;i <= n;i++){
            f[i] = Math.max(f[i - 1],f[i - 2] + nums[i - 1]);
        }
        return f[n];
    }

剑指 Offer II 090. 环形房屋偷盗 —- 序列型动态规划

动态规划刷题攻略(二)

动态规划刷题攻略(二)动态规划刷题攻略(二) 小结:

动态规划刷题攻略(二)

买卖股票系列问题

121. 买卖股票的最佳时机

动态规划刷题攻略(二)

动态规划刷题攻略(二)

    public int maxProfit(int[] prices) {
        int minPrice = Integer.MAX_VALUE;
        int maxProfit = 0;
        for(int i = 0;i < prices.length;i++){
            if(prices[i] < minPrice){
                minPrice = prices[i];
            }else if(prices[i] - minPrice > maxProfit){
                maxProfit = prices[i] - minPrice;
            }
        }
        return maxProfit;
    }

122. 买卖股票的最佳时机 II

动态规划刷题攻略(二)

只看相邻两点!!!! 

动态规划刷题攻略(二)

    public int maxProfit(int[] prices) {
        int res = 0;
        for(int i = 0;i < prices.length - 1;i++){
            if(prices[i + 1] - prices[i] > 0){
                res += prices[i + 1] - prices[i];
            }
        }
        return res;
    }

123. 买卖股票的最佳时机 III

题目大意和I,II基本相似

只能最多两次买卖

所以需要记录已经买卖了多少次

动态规划组成部分一:确定状态

记录阶段

动态规划刷题攻略(二)

动态规划刷题攻略(二)动态规划刷题攻略(二) 最后一步

动态规划刷题攻略(二)动态规划刷题攻略(二) 思考:需要把今天的红利加上 

动态规划刷题攻略(二)

子问题 

动态规划刷题攻略(二)

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

动态规划组成部分三:初始条件和边界情况

动态规划刷题攻略(二)

动态规划组成部分四:计算顺序

动态规划刷题攻略(二)

    public int maxProfit(int[] prices) {
        int n = prices.length;
        if(n == 0){
            return 0;
        }
        int[][] f = new int[n + 1][5 + 1];
        //初始条件
        //刚开始(前0天),处于阶段1,最大利润为0
        f[0][1] = 0;
        f[0][2] = f[0][3] = f[0][4] = f[0][5] = Integer.MIN_VALUE;
        for(int i = 1;i <= n;i++){
            //1,3,5
            for(int j = 1;j <= 5;j += 2){
                //max{f[i - 1][j],f[i - 1][j - 1] + Pi - 1 - Pi - 2}
                f[i][j] = f[i - 1][j];
                if(j > 1 && i > 1 && f[i - 1][j - 1] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j - 1] + prices[i - 1] - prices[i - 2]);
                }
            }
            for(int j = 2;j <= 5;j += 2){
                //max{f[i - 1][j] + Pi - 1 - Pi - 2,f[i - 1][j - 1],f[i - 1][j - 2] + Pi-1 - Pi-2}
                f[i][j] = f[i - 1][j - 1];
                if(i > 1 && f[i - 1][j] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j] + prices[i - 1] - prices[i - 2]);
                }
                if(j > 2 && i > 1 && f[i - 1][j - 2] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j - 2] + prices[i - 1] - prices[i - 2]);
                }
            }
        }
        return Math.max(Math.max(f[n][1],f[n][3]),f[n][5]);
    }

188. 买卖股票的最佳时机 IV

动态规划刷题攻略(二)

思考:为啥是 N / 2 ?

如果K > N / 2,并且买了超过一半的次数;此时,一定有几天是连着买卖的(即第一天买,第二天卖,第三天买,第四天卖,第五条买….);此时可以看作第一天买,第N天买,中间的过程忽略不看,不管咋样买卖的,都可以等价的看作任意一次买卖

动态规划组成部分一:确定状态

动态规划刷题攻略(二)

动态规划刷题攻略(二)

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

动态规划组成部分三:初始条件和边界情况

动态规划刷题攻略(二)

动态规划组成部分四:计算顺序

动态规划刷题攻略(二)

    //注意大小写K的区别
    public int maxProfit(int K, int[] prices) {
        int n = prices.length;
        if(n == 0){
            return 0;
        }
        int i, j, k;
        //k > n / 2时,可以看做,任意多次的买卖股票II
        if(K > n / 2){
            int result = 0;
            for(i = 0;i < n - 1;i++){
                result += Math.max(prices[i + 1] - prices[i],0);
            }
            return result;
        }
        int[][] f = new int[n + 1][2 * K + 1 + 1];
        //初始条件
        //刚开始(前0天),处于阶段1,最大利润为0
        f[0][1] = 0;
        for(k = 2;k <= 2 * K + 1;k++){
            f[0][k] = Integer.MIN_VALUE;
        }
        for(i = 1;i <= n;i++){
            //1,3,5
            for(j = 1;j <= 2 * K + 1;j += 2){
                //max{f[i - 1][j],f[i - 1][j - 1] + Pi - 1 - Pi - 2}
                f[i][j] = f[i - 1][j];
                if(j > 1 && i > 1 && f[i - 1][j - 1] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j - 1] + prices[i - 1] - prices[i - 2]);
                }
            }
            for(j = 2;j <= 2 * K + 1;j += 2){
                //max{f[i - 1][j] + Pi - 1 - Pi - 2,f[i - 1][j - 1],f[i - 1][j - 2] + Pi-1 - Pi-2}
                f[i][j] = f[i - 1][j - 1];
                if(i > 1 && f[i - 1][j] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j] + prices[i - 1] - prices[i - 2]);
                }
                if(j > 2 && i > 1 && f[i - 1][j - 2] != Integer.MIN_VALUE){
                    f[i][j] = Math.max(f[i][j],f[i - 1][j - 2] + prices[i - 1] - prices[i - 2]);
                }
            }
        }
        int res = Integer.MIN_VALUE;
        for(i = 1;i <= 2 * K + 1;i += 2){
            res = Math.max(res,f[n][i]);
        }
        return res;
    }

 序列 + 状态型动态规划小结

动态规划刷题攻略(二)

动态规划刷题攻略(二)

最长序列型动态规划

动态规划刷题攻略(二)

大部分序列型题目通常也是坐标型的,

动态规划刷题攻略(二)

比如这道序列型的题目也可以用坐标型的方法去做(之前的)

动态规划刷题攻略(二)

动态规划组成部分一:确定状态

最后一步

动态规划刷题攻略(二)

子问题 

动态规划刷题攻略(二)

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

动态规划组成部分三:初始条件和边界情况

动态规划刷题攻略(二)

动态规划组成部分四:计算顺序

动态规划刷题攻略(二)

public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        if(n == 0){
            return 0;
        }
        int[] f = new int[n];
        int res = 0;
        for(int j = 0;j < n;j++){
            //case 1:
            f[j] = 1;
            //case 2:
            for(int i = 0;i < j;i++){
                if(nums[i] < nums[j] && f[i] + 1 > f[j]){
                    f[j] = f[i] + 1;
                }
            }
            res = Math.max(res,f[j]);
        }
        return res;
    }

思考:如何做到nlog(n)[第七讲会讲]

354. 俄罗斯套娃信封问题

动态规划刷题攻略(二)

动态规划组成部分一:确定状态

动态规划刷题攻略(二)

子问题

动态规划刷题攻略(二)

动态规划组成部分二:转移方程 

动态规划刷题攻略(二)

动态规划组成部分三:初始条件和边界情况

动态规划刷题攻略(二)

动态规划组成部分四:计算顺序

f[0],f[1],…,f[N – 1]

时间复杂度O(N^2),空间复杂度O(N)

    public int maxEnvelopes(int[][] envelopes) {
        if(envelopes.length == 0){
            return 0;
        }
        Arrays.sort(envelopes,new Comparator<int[]>(){
            public int compare(int[] a,int[] b){
                //长度相等,宽度任意排序
                if(a[0] == b[0]){
                    return a[1] - b[1];
                }else{
                    //长度从小到大
                    return a[0] - b[0];
                }
            }
        });
        int n = envelopes.length;
        int[] f = new int[n];
        int res = 0;
        for(int i = 0;i < n;i++){
            f[i] = 1;
            for(int j = 0;j < i;j++){
                //信封 j 能被放进信封 i
                if(envelopes[j][0] < envelopes[i][0] && envelopes[j][1] < envelopes[i][1]){
                    f[i] = Math.max(f[i],f[j] + 1);
                }
            }
            res = Math.max(res,f[i]);
        }
        return res;
    }

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由半码博客整理,本文链接:https://www.bmabk.com/index.php/post/110910.html

(0)

相关推荐

半码博客——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!