leetcode part9 动态规划

/**
动态规划(设计动态规划算法以解决问题)
动态规划题目的代码量都不大

leetcode 198. 打家劫舍
写出动态规划方程,迭代方程如下
(1)初始条件
    dp[0]=nums[0]
    dp[1]=max(nums[0],nums[1])
(2)迭代公式
    dp[i]=max(dp[i-1],nums[i]+dp[i-2])

**/

#include<vector>
#include<algorithm>
#include<iostream>
using namespace std;

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

        vector<int> dp;
        dp.push_back(nums[0]);
        dp.push_back(max(nums[0],nums[1]));

        for(int i=2;i<nums.size();i++){
            dp.push_back(max(dp[i-1],dp[i-2]+nums[i]));
        }
        return dp[dp.size()-1];
    }
};

int main(){
    int a[5]={2,7,9,3,1};
    vector<int> nums;
    for(int i=0;i<5;i++){
        nums.push_back(a[i]);
    }
    Solution s;
    cout<<s.rob(nums)<<endl;

    return 0;
}
#include<iostream>
#include<vector>
using namespace std;

/**
leetcode 53. 最大子序和
如果将dp数组定义成从第0个字符到i个字符构成的字符串中
的最大自序和,则dp[i+1]和dp[i]之间的关系并不连续
故而在这里将dp[i]定义成从第0个字符到第i个字符构成的字符串
中最大子序和,且该子序列最后一个字符必须是字符串的第i个字符
则dp数组中的最大值即为返回值(而并不是最后一个数值)
**/

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==0){
            return 0;
        }
        if(nums.size()==1){
            return nums[0];
        }
        vector<int> dp;
        dp.push_back(nums[0]);
        int max_value=nums[0];

        for(int i=1;i<nums.size();i++){
            if(dp[i-1]>0){
                dp.push_back(dp[i-1]+nums[i]);
                if(dp[i-1]+nums[i]>max_value){
                    max_value=dp[i-1]+nums[i];
                }
            }
            else{
                dp.push_back(nums[i]);
                if(nums[i]>max_value){
                    max_value=nums[i];
                }
            }
        }
        return max_value;
    }
};

int main(){
    int a[9]={-2,1,-3,4,-1,2,1,-5,4};
    vector<int> nums;
    for(int i=0;i<9;i++){
        nums.push_back(a[i]);
    }

    Solution s;
    cout<<s.maxSubArray(nums)<<endl;


    return 0;
}

#include<iostream>
#include<vector>
using namespace std;

/**
leetcode 322. 零钱兑换
给定不同面额的硬币 coins 和一个总金额 amount
编写一个函数来计算可以凑成总金额所需的最少的硬币个数
如果没有任何一种硬币组合能组成总金额,返回 -1

算法:
    dp[i]数组表示总金额数为i时,所需要的钞票最少张数
    dp[0]  无意义
    写出dp[N] 数组的递推公式即可


**/

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        if(amount==0){
            return 0;
        }
        int dp[amount+1]={-1};
        for(int i=0;i<coins.size();i++){
            if(coins[i]<amount){
                // 大于当前数值的硬币并不会被用
                dp[coins[i]]=1;
            }
            if(coins[i]==amount){
                return 1;
            }
        }

        for(int j=1;j<amount+1;j++){
            if(dp[j]==1){
                continue;
            }
            else{
                int min_count=0x7fffffff;
                // C++中的int整型是4个字节,共32个bit位
                bool visible=false;
                for(int k=0;k<coins.size();k++){
                    if(coins[k]>j){
                        continue;
                    }
                    if(dp[j-coins[k]]>0 and dp[j-coins[k]]+1<min_count){
                        min_count=dp[j-coins[k]]+1;
                        visible=true;
                    }
                }
                if(visible){
                    dp[j]=min_count;
                }
                else{
                    dp[j]=-1;
                }
            }
        }
        return dp[amount];
    }
};

int main(){
    int a[8]={27,398,90,323,454,413,70,315};
    vector<int> nums;
    for(int i=0;i<8;i++){
        nums.push_back(a[i]);
    }
//    vector<int> nums;
//    nums.push_back(1);

    Solution s;
    cout<<s.coinChange(nums,6131)<<endl;

    return 0;
}
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

/**
leetcode 120. 三角形最小路径和



**/

class Solution {
public:
    int minimumTotal(vector<vector<int> >& triangle) {
        if(triangle.size()==0){
            return 0;
        }
        if(triangle.size()==1){
            return triangle[0][0];
        }
        vector<vector<int> > result;

        vector<int> line1;
        line1.push_back(triangle[0][0]);
        result.push_back(line1);

        vector<int> line2;
        line2.push_back(triangle[0][0]+triangle[1][0]);
        line2.push_back(triangle[0][0]+triangle[1][1]);

        result.push_back(line2);

        vector<int> temp_line;

        for(int i=2;i<triangle.size();i++){
            temp_line.clear();
            temp_line.push_back(result[i-1][0]+triangle[i][0]);
            for(int j=1;j<triangle[i].size()-1;j++){
                temp_line.push_back(triangle[i][j]+min(result[i-1][j-1],result[i-1][j]));
            }
            temp_line.push_back(result[i-1][i-1]+triangle[i][i]);
            result.push_back(temp_line);
        }

//        for(int m=0;m<result.size();m++){
//            for(int n=0;n<result[m].size();n++){
//                cout<<result[m][n]<<",";
//            }
//            cout<<endl;
//        }
//
//        cout<<"during debug "<<endl;

        return *min_element(result[result.size()-1].begin(),result[result.size()-1].end());
    }
};

int main(){
    vector<int> line0;
    line0.push_back(2);

    vector<int> line1;
    line1.push_back(3);
    line1.push_back(4);

    vector<int> line2;
    line2.push_back(6);
    line2.push_back(5);
    line2.push_back(7);

    vector<int> line3;
    line3.push_back(4);
    line3.push_back(1);
    line3.push_back(8);
    line3.push_back(3);

    vector<vector<int> > triangle;
    triangle.push_back(line0);
    triangle.push_back(line1);
    triangle.push_back(line2);
    triangle.push_back(line3);



    Solution s;
    cout<<s.minimumTotal(triangle)<<endl;

    return 0;
}
#include<vector>
#include<iostream>
using namespace std;

/**
leetcode 64. 最小路径和
给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,
使得路径上的数字总和为最小。
说明:每次只能向下或者向右移动一步。
**/

class Solution {
public:
    int minPathSum(vector<vector<int> >& grid) {
        // 将二维矩阵第一行和第一列的数字进行初始化
        // 从起始点到达第一行或者第一列的点的路径是唯一的
        int m=grid.size();
        int n=grid[0].size();

        for(int i=1;i<n;i++){
            grid[0][i]+=grid[0][i-1];
        }

        for(int j=1;j<m;j++){
            grid[j][0]+=grid[j-1][0];
        }

        for(int i=1;i<m;i++){
            for(int j=1;j<n;j++){
                grid[i][j]+=min(grid[i][j-1],grid[i-1][j]);
            }
        }
        return grid[m-1][n-1];
    }
};

int main(){
    vector<vector<int> > grid;
    vector<int> line1;
    int a[3]={1,3,1};

    for(int i=0;i<3;i++){
        line1.push_back(a[i]);
    }
    grid.push_back(line1);

    a[1]=5;
    line1.clear();
    for(int i=0;i<3;i++){
        line1.push_back(a[i]);
    }

    grid.push_back(line1);

    a[0]=4;
    a[1]=2;
    line1.clear();
    for(int i=0;i<3;i++){
        line1.push_back(a[i]);
    }

    grid.push_back(line1);

    Solution s;
    cout<<s.minPathSum(grid)<<endl;


    return 0;
}

 

### LeetCode 上的回溯算法练习题 #### N皇后问题 N皇后问题是经典的回溯算法应用之一。该问题的目标是在 n×n 的国际象棋棋盘上放置 n 个皇后,使得它们互相之间不能攻击对方。具体实现中,递归函数 `backtracking` 的作用是在棋盘上逐行放置皇后,并检查每一步是否符合规则[^1]。 ```cpp void backtracking(int n, int row, vector<string>& chessboard) { if (row == n) { // 所有皇后都成功放置的情况 result.push_back(chessboard); return; } for (int col = 0; col < n; ++col) { if (isValid(row, col, chessboard)) { chessboard[row][col] = &#39;Q&#39;; // 放置皇后 backtracking(n, row + 1, chessboard); // 进入下一行放皇后 chessboard[row][col] = &#39;.&#39;; // 回溯,撤销当前格子上的皇后 } } } ``` 此代码片段展示了如何利用回溯法解决 N 皇后问题的核心逻辑。 #### 子集 II 去重 对于含有重复元素的数据集合,在求解其所有不重复子集时可以采用特定策略去除冗余项。当面对已排序数组中的重复情况时,可以通过记录前一访问过的元素来进行过滤操作[^2]。 ```cpp if (i > start && nums[i] == nums[i - 1]) continue; ``` 上述 C++ 片段用于跳过相同元素以避免生成重复组合。 #### 复原 IP 地址 另一个有趣的例子是从给定字符串构建有效的 IPv4 地址列表的任务。这同样依赖于回溯技术来探索所有潜在分割方案并验证合法性[^3]。 ```python def restoreIpAddresses(s: str): res = [] path = [] def backtrack(start=0): if len(path) == 4 and start == len(s): res.append(&#39;.&#39;.join(path)) return for length in range(1, min(len(s)-start+1, 4)): part = s[start:start+length] if not isValidPart(part): break path.append(part) backtrack(start + length) path.pop() backtrack() return res ``` 这段 Python 实现了寻找所有可能的有效 IP 地址的过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值