代码随想录算法训练营 day42 || 01背包问题,416. 分割等和子集

视频讲解:

带你学透0-1背包问题!| 关于背包问题,你不清楚的地方,这里都讲了!| 动态规划经典问题 | 数据结构与算法_哔哩哔哩_bilibili

带你学透01背包问题(滚动数组篇) | 从此对背包问题不再迷茫!_哔哩哔哩_bilibili

动态规划之背包问题,这个包能装满吗?| LeetCode:416.分割等和子集_哔哩哔哩_bilibili

01背包问题

思路:总结一下自己的思路体会:

  • 01背包问题的维度分别是物品数量,物品的特征体现(如重量);
  • 01背包问题的递归公式从前i-1种物品的考虑,然后考虑当前的第i种物品,其实这和我们前面所做的双指针类型的题目一样,都是对于数组开始从无到有的一个个开始遍历的,所有前面已经遍历完成的一定包含了前面的元素所有可行的最佳情况,所以动态规划本质上也是一种贪心;
  • 关于状态转换,我觉得最难以理解的就是,如果当前物品放不进去,就是直接继承上一层的同列元素,这是我认为01背包中最难以理解的部分,也是我目前使用说“前i-1种操作都包含在dp[i-1][j]”,所以当前放不进去的话就可以直接继承下来,我暂时还说服自己。
  • 最后想要学习的一点就是01背包考虑的是怎么性价比最大的放入元素。
  • 第二点是重量维度进行遍历时需要从后往前遍历,可以减少某些小重量物品的重复加入!!!那么反过来想,支持重复加入的从前遍历,是否就是完全背包问题的解法?
// 时间复杂度O(n^2)
// 空间复杂度O(n)或O(n^2)

import java.util.*;

public class runafter {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int M = scanner.nextInt();
        int N = scanner.nextInt();
        int[] weights = new int[M];
        int[] values = new int[M];

        for(int i=0; i=weights[0])
                dp[0][i] = values[0];
//        for (int i=0; i=weights[i]){
                    dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-weights[i]]+values[i]);
                }
                else
                    dp[i][j] = dp[i-1][j];
            }
        }

        System.out.println(dp[M-1][N]);

        int[] DP = new int[N+1];
        for(int i=0; i=1; j--){        // 重量
                if(j >= weights[i])
                    DP[j] = Math.max(DP[j], DP[j - weights[i]] + values[i]);
            }
        }
        System.out.println(DP[N]);
        return;
    }
}

416. 分割等和子集

思路:在拿到这道题目时,其实第一想法是回溯,去不断试错当前的子集和;但回溯的时间复杂度必定是指数级,大概率会超时。其次想到贪心,走动态规划,因为这是一个不断加入元素尝试的过程,所以是动规。那么再看分割子集,其实也是一个不断加入元素从一个集合至另一个集合的过程,所以可以视作背包问题,并且每个元素可以取一次,所以是01背包问题,下面需要处理的就是动态规划,我们的目标是操作数组和,所以和就是本题所理解的重量,以物品数和数组和作为两个维度构建数据即可求解。

class Solution {
    public boolean canPartition(int[] nums) {
        
        if(nums.length == 1)
            return false;

        int m = nums.length;
        int n = 0;
        for(int i=0; i= nums[0]){
        //         dp[0][j] = nums[0];
        //     }
        
        // for(int i=1; i=1; j--){
        //         if(j>=nums[i]){
        //             dp[i][j] = Math.max(dp[i-1][j], dp[i-1][j-nums[i]]+nums[i]);
        //         }
        //         else
        //             dp[i][j] = dp[i-1][j];
                
        //         if(dp[i][j] == n/2)
        //             return true;
        //     }
        // }
        int[] dp = new int[n/2+1];
        for(int i=0; i=1; j--){    // 类似于重量
                if(j >= nums[i])
                    dp[j] = Math.max(dp[j], dp[j-nums[i]]+nums[i]);
                if(dp[j] == n/2)
                    return true;
            }
        }
        return false;
               
    }
}

 

你可能感兴趣的:(算法)