Day1-2021年1月9日-【玩转算法面试0-1背包问题】

2021年1月9日 时间都去哪了?囧

1.0-1背包问题
2.LIS问题:力扣300. 最长递增子序列
3.上午测了核酸。
4.傍晚跑步

总而言之,今天没有多少工作量。昨天有同学买了【Java主流技术栈SSM+SpringBoot商铺系统】,自己看了看,需要安装好些软件,还需要javaweb的基础。

明天计划:力扣题目刷到150。javaweb进行下去,或者学习计算机网络。

下面的笔记的图片没有上传成功,自己是先用Typora做的。明天试试解决。
解决办法:Typora笔记上传到CSDN解决图片问题—亲测有效!

转到2021.1.9-2021.1.31的learning record 首页

关注点:
剑指offer;leetcode。我刷了400道吧。包括剑指offer的题目70多道,剑指特别难的题可以放弃5-10个。大厂面试每轮都会有一到两到代码题,只要代码题都写出来,即使是别的问题回答的很烂,大概率也能过。剑指offer里的题出题频率还是蛮高的。重点还是代码就是LeetCode。中等,要很快的做出来,刷题要达到信手拈来的程度。刷题,刷题,刷题,很重要。

数据结构,听听视频,先学一遍,再刷题,知道数据结构有什么类型。宽度优先遍历,广度优先遍历,二组查找,数组,链表,这些都挺重要的。可以跟着视频学可以的,先学一遍数据结构,知道题目的类型。

[算法与数据结构-综合提升C++版(快速应对面试)。这个明天可以看看。在下载了。]

正文:

9-5 0-1背包问题

0-1背包问题 视频题

贪心算法:优先放入平均价值最高的物品。通过实际的案例对比,发现是不可以的。贪心算法是无法解决这个问题的。不是全局最优解。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t76tmEoI-1610200560995)(第9章 动态规划基础.assets/image-20210109141239005.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LKTG3eQQ-1610200561001)(第9章 动态规划基础.assets/image-20210109141301474.png)]

0-1背包问题的状态转移方程。

F(n,c):将n个物品装进容量为c的背包,使得价值最大。

F(i,c)=max( F(i-1,c) , v(i) + F( i-1,c- w(i) ) )

F(i-1,c):第i个物品不放进背包中。

F( i-1,c- w(i) ) :第i个物品放进背包中,相应的,背包容量-物品i的重量w(i)。

(1)递归方法

public class p9_ex5_1 {
    private int knapsack01(int[] w, int[] v, int c) {
        int n = w.length;
        //用[0,1,... ...,index]的物品来填充体积为c的背包的最大价值
        // n-1 是说 物品 0到n-1
        return bestValue(w, v, n - 1, c);
    }

    private int bestValue(int[] w, int[] v, int index, int c) {
        // 边界条件 index是递减的,容量c也是递减的。
        if (index < 0 || c < 0) {
            return 0;
        }
        // 这里的 res 是说第 index 个物品 不放入背包中。
        int res = bestValue(w, v, index - 1, c);
        // 判断第 index 个物品的体积是否 小于等于背包的剩余容量。
        // 否则直接返回上面得到的res。
        if (c >= w[index]) {
            //res2 是指放入index的物品,
            int res2 = v[index] + bestValue(w, v, index - 1, c - w[index]);
            res = Math.max(res, res2);
        }
        return res;
    }
}

(2)记忆搜索

这里的记忆,是存储res。w,v,index,c中的index,c作为索引。w,v,是数组哦。

import java.util.Arrays;

public class p9_ex5_2 {
    public static void main(String[] args) {
        int[] w = new int[]{1, 2, 3};
        int[] v = new int[]{6, 10, 12};
        int c = 5;
        System.out.println(knapsack01(w, v, c));
    }

    static int[][] memo;

    private static int knapsack01(int[] w, int[] v, int c) {
        int n = w.length;
        // 这里的初始化 容量是 从0到c,是c+1个数。
        memo = new int[n][c + 1];
        for (int i = 0; i < n; i++) {
            Arrays.fill(memo[i], -1);
        }
        // n-1 是说 物品 0到n-1
        return bestValue(w, v, n - 1, c);
    }

    private static int bestValue(int[] w, int[] v, int index, int c) {
        // 边界条件 index是递减的,容量c也是递减的。
        if (index < 0 || c < 0) {
            return 0;
        }
        if (memo[index][c] != -1) {
            return memo[index][c];
        }
        // 这里的 res 是说第 index 个物品 不放入背包中。
        int res = bestValue(w, v, index - 1, c);
        // 判断第 index 个物品的体积是否 小于等于背包的剩余容量。
        // 否则直接返回上面得到的res。
        if (c >= w[index]) {
            //res2 是指放入index的物品,
            int res2 = v[index] + bestValue(w, v, index - 1, c - w[index]);
            res = Math.max(res, res2);
        }
        memo[index][c] = res;
        return res;
    }
}

(3)动态规划

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ev0eEaDO-1610200561011)(第9章 动态规划基础.assets/image-20210109153720412.png)]

如果能理解上图,就理解了做题的思路了。

时间复杂度O(nC),空间复杂度O(nC)

import java.util.Arrays;

public class p9_ex5_3 {
    public static void main(String[] args) {
        int[] w = new int[]{1, 2, 3};
        int[] v = new int[]{6, 10, 12};
        int c = 5;
        System.out.println(knapsack01(w, v, c));
    }

    private static int knapsack01(int[] w, int[] v, int c) {
        int n = w.length;
        if (n == 0) {
            return 0;
        }
        // c+1是为了遍历0到c这些重量。
        int[][] dp = new int[n][c + 1];
        // dp 第0行的元素是多少。
        // c+1 个元素 遍历列元素。
        // 这里的j是指的容量c的遍历啊。遍历0到c这些重量。
        // 因为下面的下面的双重for循环会使用i-1,所有先去计算得到i=0的数据。
        for (int j = 0; j <= c; j++) {
            // 如果剩余容量j≥第0个物品的重量,那就可以将第0个物品放入背包,此时背包的价值为v[0]
            dp[0][j] = j >= w[0] ? v[0] : 0;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= c; j++) {
                // dp[i][j]是指考虑0到i这些物品,且容积为j的背包,所得到的最大值是多少。
                // 1.不考虑第i件物品。
                dp[i][j] = dp[i - 1][j];
                // 剩余的容量j仍然可以将重量为w[i]的物品装进去。
                if (j >= w[i]) {
                    dp[i][j] = Math.max(dp[i][j], v[i] + dp[i - 1][j - w[i]]);
                }
            }
        }
        // dp初始化大小为[n][c+1]
        return dp[n - 1][c];
    }
}

img


img

(4)背包问题的优化

F(i,c)=max( F(i-1,c) , v(i) + F( i-1,c- w(i) ) )

F(i-1,c):第i个物品不放进背包中。

F( i-1,c- w(i) ) :第i个物品放进背包中,相应的,背包容量-物品i的重量w(i)。

第i行元素,只是依赖于第i-1行元素,理论上只保留两行元素即可。

代码如下:

public class p9_ex5_3_2_1 {
    public static void main(String[] args) {
        int[] w = new int[]{1, 2, 3};
        int[] v = new int[]{6, 10, 12};
        int c = 5;
        System.out.println(knapsack01(w, v, c));
    }

    private static int knapsack01(int[] w, int[] v, int c) {
        int n = w.length;
        if (n == 0) {
            return 0;
        }
        int[][] dp = new int[2][c + 1];
        for (int j = 0; j <= c; j++) {
            dp[0][j] = j >= w[0] ? v[0] : 0;
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j <= c; j++) {
                dp[i % 2][j] = dp[(i - 1) % 2][j];
                if (j >= w[i]) {
                    dp[i % 2][j] = Math.max(dp[i % 2][j], v[i] + dp[(i - 1) % 2][j - w[i]]);
                }
            }
        }
        return dp[(n - 1) % 2][c];
    }
}

[视频9-6 15min30s讲到了 0-1背包问题的变种]

(1)完全背包问题

完全背包问题:每个物品可以无限次的使用。这里由于背包的容量有限制,所以实际上每个物品的个数也会被限制,所以可以将完全背包问题转化为0-1背包问题。

(2)多重背包问题

多重背包问题:每个物品不止1个,而是有num[i]个。感觉就是上面问题的拓展延伸。

(3)多维费用的背包问题

多维费用的背包问题:考虑体积和重量两个维度

(4)等等变形的问题

[视频9.8-9]

最长上升子序列

300. 最长上升子序列

(1)LIS问题的o(n2)的解法

LIS(i)表示在【0…i】的范围内,选择数字num[i]作为结尾,可以获得的最长上升子序列的长度。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C1DmLSwo-1610200561021)(第9章 动态规划基础.assets/image-20210109212248191.png)]

max(j<i)指的是在所有的可能中选择最大值。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oSxGMqKs-1610200561024)(第9章 动态规划基础.assets/image-20210109213530842.png)]

import java.util.Arrays;

public class p9_ex6_300 {
    public int lengthOfLIS(int[] nums) {
        int n = nums.length;
        if (n == 0) {
            return 0;
        }
        // dp[i]表示以nums[i]为结尾的最长上升子序列的长度
        int[] dp = new int[n];
        // dp[i]初始值要赋值为1
        Arrays.fill(dp, 1);
        for (int i = 1; i < n; i++) {
            // 这里的第二重for循环,是去考察num[i]之前所有的元素
            for (int j = 0; j < i; j++) {
                if (nums[j] < nums[i]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
        }
        // 取得dp数组中的最大值
        int res = 1;
        for (int i = 0; i < n; i++)
            res = Math.max(res, dp[i]);
        return res;
    }
}
(2)LIS问题的o(log2n)的解法

去网络自学

376. 摆动序列【课后题】

(1)动态规划时间复杂度O(n2),状态转移方程

当nums[i] > nums[j] && i > j,up[i] = down[j] + 1
当nums[i] < nums[j] && i > j,down[i] = up[j] + 1


(2)简化版,时间复杂度O(n)


[视频9.8-9 26min 开始第二个视频]

最长公共子序列

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qM9WORSl-1610203753573)(第9章 动态规划基础.assets/image-20210109221138118.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HPDeNoGj-1610203753581)(第9章 动态规划基础.assets/image-20210109223300922.png)]

自行练习解决这个题目

(1)递归

(2)记忆化搜索

(3)动态规划

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oI6Jgqzl-1610203753586)(第9章 动态规划基础.assets/image-20210109221155714.png)]

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值