LeetCode典型题——动态规划

本文探讨了LeetCode中涉及动态规划的典型题目,包括343, 62, 198, 213, 337和300等,解析了动态规划的解题思路,如状态转移方程,并提及了两种优化方法:优化1和优化2,旨在减少内存使用。" 132771506,19687618,使用Python与OpenCV在图像上叠加标签图,"['计算机视觉', '图像处理', 'Python编程', 'OpenCV库']

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这里插入图片描述
在这里插入图片描述

343

在这里插入图片描述
在这里插入图片描述

class Solution {
private:
    vector<int> memo;

    int breakInteger(int n){

        if(n == 1)
            return 1;

        if(memo[n] != -1)
            return memo[n];

        int res = -1;
        for(int i = 1 ; i < n ; i ++)
        {
            int tmp = max(i * (n - i) , i * breakInteger(n - i));	//别忘记  i*(n-i)
            res = max(res, tmp);
        }
           
        memo[n] = res;
        return res;
    }

public:
    int integerBreak(int n) {
       
        memo = vector<int>(n+1, -1);
        return breakInteger(n);
    }
};

动态规划

class Solution {
private:
    vector<int> memo;


public:
    int integerBreak(int n) {
       
        memo = vector<int>(n+1, -1);
        
        memo[1] = 1;
        for(int i=2; i<=n; i++)
        {
            for(int j=1; j<=i-1; j++)
            {
                int tmp = max(j*(i-j), j*memo[i-j]);
                memo[i] = max(memo[i], tmp);
            }
        }
        
        return memo[n];
    }
};

62

在这里插入图片描述

class Solution {
public:
    int uniquePaths(int m, int n) {
        
        memo = vector<vector<int>>(m, vector<int>(n, 1));       //memo[i][j] 保存到 节点[i][j] 的路径个数
                                                                //memo[i][j] = memo[i-1][j] + memo[i][j-1]
        for(int i=1; i<m; i++)
           for(int j=1; j<n; j++)
               memo[i][j] = memo[i-1][j] + memo[i][j-1];
        
        return memo[m-1][n-1];
        
    }
    
private:
    vector<vector<int>> memo;
};

198

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    int rob(vector<int>& nums) {
        
        memo = vector<int>(nums.size(), -1);
        
        return help(nums, 0);
        
    }
    
private:
    vector<int> memo;
    
    int help(vector<int>& nums, int index)
    {
        if(index >= nums.size())
            return 0;
        
        if(memo[index] != -1)
            return memo[index];
        
        int ret = 0;
        for(int i=index; i<nums.size(); i++)
        {
            ret = max(nums[i]+help(nums, i+2), ret);
        }
        
        memo[index] = ret;
        return ret;
    }
};

动态规划

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        if( n == 0 )
            return 0;

        // the max profit for robbing nums[0...i]
        vector<int> memo(n, 0);
        memo[0] = nums[0];
        for(int i = 1 ; i < n ; i ++)
            memo[i] = max(memo[i - 1],
                          nums[i] + (i - 2 >= 0 ? memo[i - 2] : 0));

        return memo[n-1];
    }
    
private:
    vector<int> memo;    
};

213

在这里插入图片描述

class Solution {
public:
    int rob(vector<int>& nums) {
        
        int n = nums.size();
        if( n == 0 )
            return 0;
        if(n == 1)
            return nums[0];

        // the max profit for robbing nums[0...i-1]
        vector<int> memo(n, 0);
        memo[0] = nums[0];
        for(int i = 1 ; i < n-1 ; i ++)
            memo[i] = max(memo[i - 1],
                          nums[i] + (i - 2 >= 0 ? memo[i - 2] : 0));

        // the max profit for robbing nums[1...i]
        vector<int> memo1(n, 0);
        memo1[0] = 0;
        for(int i = 1 ; i < n; i ++)
            memo1[i] = max(memo1[i - 1],
                          nums[i] + (i - 2 >= 0 ? memo1[i - 2] : 0));

        return max(memo[n-2], memo1[n-1]);
    }
    
private:
    vector<int> memo;
    vector<int> memo1;
    
};

337

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    int rob(TreeNode* root) {
        
        if(!root)
            return 0;
        
        int ret = help(root);
        return ret;
    }
    
private:
    unordered_map<TreeNode*, int> memo;
    
    int help(TreeNode *node)
    {
        if(!node)
            return 0;
        
        if(memo.find(node) != memo.end())
            return memo[node];
        
        int tmp = 0;
        if(node->left)
            tmp += help(node->left->left) + help(node->left->right);
        if(node->right)
            tmp += help(node->right->left) + help(node->right->right);
        
        tmp = max(node->val+tmp, help(node->left)+help(node->right));      //比较:当前节点+左、右节点的子树  左子树+右子树
        memo[node] = tmp;
        
        return tmp;
    }
};

300

在这里插入图片描述

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        
        if(nums.size() == 0)
            return 0;
        
        memo = vector<int>(nums.size(), 1);     //memo[i]:以 nums[i] 为结尾的最长上升子序列的长度
        
        for(int i=1; i<nums.size(); i++)
            for(int j=0; j<i; j++)
            {
                if(nums[j] < nums[i])
                    memo[i] = max(memo[i], memo[j]+1);
            }
        
        sort(memo.begin(), memo.end());
        return memo[nums.size()-1];
    }
    
private:
    vector<int> memo;
};

动态规划

/**
 * Definition for an interval.
 * struct Interval {
 *     int start;
 *     int end;
 *     Interval() : start(0), end(0) {}
 *     Interval(int s, int e) : start(s), end(e) {}
 * };
 */

bool compare(const Interval& a, const Interval& b)
{
    if(a.start != b.start)
        return a.start < b.start;
    return a.end < b.end;
}

class Solution {
public:
    int eraseOverlapIntervals(vector<Interval>& intervals) 
    {
        
        if(intervals.size() == 0)
            return 0;
        
        sort(intervals.begin(), intervals.end(), compare);
        
        //memo[i] : intervals[0...i]所包含的最大不重叠区间个数
        memo = vector(intervals.size(), 1);
        
        for(int i=1; i<intervals.size(); i++)
            for(int j=0; j<i; j++)
            {
                if(intervals[j].end <= intervals[i].start)
                    memo[i] = max(memo[i], memo[j]+1);
            }
        
        sort(memo.begin(), memo.end());
        
        return intervals.size() - memo[intervals.size()-1];
    }
    
private:
    vector<int> memo;
};

贪心

bool compare(const Interval &a, const Interval &b){
    if(a.end != b.end)
        return a.end < b.end;
    return a.start < b.start;
}

/// 时间复杂度: O(n)
/// 空间复杂度: O(n)
class Solution {
public:
    int eraseOverlapIntervals(vector<Interval>& intervals) {

        if(intervals.size() == 0)
            return 0;

        sort(intervals.begin(), intervals.end(), compare);

        int res = 1;
        int pre = 0;
        for(int i = 1 ; i < intervals.size() ; i ++)
            if(intervals[i].start >= intervals[pre].end){
                res ++;
                pre = i;
            }

        return intervals.size() - res;
    }
};

在这里插入图片描述

F(i, c):在i个物体中选择,背包容量为c,价值最大
F(i, c)= max(F(i-1,c), v[i]+F(i-1,c-w[i]))

class Knapsack01{

private:
    vector<vector<int>> memo;

    // 选择 [0...index]的物品,填充容积为c的背包的最大价值
    int bestValue(const vector<int> &w, const vector<int> &v, int index, int c){

        if(c <= 0 || index < 0)
            return 0;

        if(memo[index][c] != -1)
            return memo[index][c];

        int res = bestValue(w, v, index-1, c);
        if(c >= w[index])
            res = max(res, v[index] + bestValue(w, v, index - 1, c - w[index]));
        memo[index][c] = res;
        return res;
    }

public:
    int knapsack01(const vector<int> &w, const vector<int> &v, int C){
        assert(w.size() == v.size() && C >= 0);
        int n = w.size();
        if(n == 0 || C == 0)
            return 0;

        memo = vector<vector<int>>(n, vector<int>(C+1, -1));
        return bestValue(w, v, n - 1, C);
    }
};

动态规划

在这里插入图片描述

//时间复杂度: O(n * C) 其中n为物品个数; C为背包容积
//空间复杂度: O(n * C)

class Knapsack01{

public:
    int knapsack01(const vector<int> &w, const vector<int> &v, int C){
        assert(w.size() == v.size() && C >= 0);
        int n = w.size();
        if(n == 0 || C == 0)
            return 0;

        vector<vector<int>> memo(n, vector<int>(C + 1,0));

        for(int j = 0 ; j <= C ; j ++)
            memo[0][j] = (j >= w[0] ? v[0] : 0 );

        for(int i = 1 ; i < n ; i ++)
            for(int j = 0 ; j <= C ; j ++){
                memo[i][j] = memo[i-1][j];
                if(j >= w[i])
                    memo[i][j] = max(memo[i][j], v[i] + memo[i - 1][j - w[i]]);
            }
        return memo[n - 1][C];
    }
};

优化1:
在这里插入图片描述

/// 时间复杂度: O(n * C) 其中n为物品个数; C为背包容积
/// 空间复杂度: O(C), 实际使用了2*C的额外空间
class Knapsack01{

public:
    int knapsack01(const vector<int> &w, const vector<int> &v, int C){
        assert(w.size() == v.size() && C >= 0);
        int n = w.size();
        if( n == 0 && C == 0 )
            return 0;

        vector<vector<int>> memo(2, vector<int>(C + 1, 0));

        for(int j = 0 ; j <= C ; j ++)
            memo[0][j] = (j >= w[0] ? v[0] : 0);

        for(int i = 1 ; i < n ; i ++)
            for(int j = 0 ; j <= C ; j ++){
                memo[i % 2][j] = memo[(i-1) % 2][j];
                if(j >= w[i])
                    memo[i % 2][j] = max(memo[i % 2][j], v[i] + memo[(i-1) % 2][j - w[i]]);
            }
        return memo[(n-1) % 2][C];
    }
};

优化2:只使用一行大小为C的数组

/// 时间复杂度: O(n * C) 其中n为物品个数; C为背包容积
/// 空间复杂度: O(C), 只使用了C的额外空间
class Knapsack01{

public:
    int knapsack01(const vector<int> &w, const vector<int> &v, int C){
        assert(w.size() == v.size() && C >= 0);
        intn = w.size();
        if(n == 0 || C == 0)
            return 0;

        vector<int> memo(C+1,0);

        for(int j = 0 ; j <= C ; j ++)
            memo[j] = (j >= w[0] ? v[0] : 0);

        for(int i = 1 ; i < n ; i ++)
            for(int j = C ; j >= w[i] ; j --)
                memo[j] = max(memo[j], v[i] + memo[j - w[i]]);

        return memo[C];
    }
};

在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        
        int sum = 0;
        for(int i=0; i<nums.size(); i++)
            sum += nums[i];
        
        if(sum%2 != 0)
            return false;
        
        memo = vector<vector<int>>(nums.size(), vector<int>(sum/2+1, -1));
        
        return help(nums, nums.size()-1, sum/2);
    }
    
private:
    vector<vector<int>> memo;   //memo[i][c]    -1:没记录过 
                                //              0:nums[0...i]无法填满 大小为 C 的背包
                                //              1:nums[0...i] 可以填满 大小为 C 的背包
    
    bool help(vector<int> &nums, int index, int C)      //  nums[0...index] 能否填满 大小为 C 的背包
    {
        if(C == 0)
            return true;
        
        if(index < 0 || C < 0)
            return false;
        
        if(memo[index][C] != -1)
            return (memo[index][C] == 0)?false:true;
        
        memo[index][C] = help(nums, index-1, C) || help(nums, index-1, C-nums[index]);
        
        return memo[index][C];
    }
};

在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值