动态规划笔记

283. Move Zeroes
27. Remove Element
26. Remove Duplicates from Sorted Array
80. Remove Duplicates from Sorted Array II


283. Move Zeroes

// 解法一:最直观的解法,新建一个vector res,遍历nums,将非0元素依次赋值入res即可
// 时间复杂度O(n),空间复杂度O(n)
class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        vector<int> res(nums.size(), 0);
        int index = 0;
        for(auto it = nums.begin(); it != nums.end(); ++it){
            if(*it != 0){
                res[index] = *it;
                ++index;
            }         
        }
        nums = res;
    }
};



动态规划


70.Climbing Stairs


// 解法一:递归
class Solution {
public:
    int climbStairs(int n) {
        if( n == 0 || n == 1)
            return 1;

        return climbStairs(n-1) + climbStairs(n-2);
    }
};
// 解法二:递归+记忆化搜索
class Solution {
private:
    vector<int> memo;
    int calcWays(int n){
        if(n == 0 || n == 1)
            return 1;
        if(memo[n] == -1){
            memo[n] = calcWays(n-1) + calcWays(n-2);
        }
        return memo[n];
    }

public:
    int climbStairs(int n) {
        memo = vector<int>(n+1, -1);
        return calcWays(n);
    }
};
// 解法三:动态规划
class Solution {
public:
    int climbStairs(int n) {
        // n >= 1
        vector<int> memo(n+1, -1);
        memo[0] = 1;
        memo[1] = 1;
        for( int i = 2 ; i <= n ; i ++ )
            memo[i] = memo[i-1] + memo[i-2];
        return memo[n];
    }
};

120. Triangle


// 自上向下
class Solution {
public:
    int minimumTotal(vector<vector<int>>& triangle) {
        vector<vector<int>> res(triangle.size(), vector<int>(triangle.size(), -1));

        for(int i = 0; i < triangle.size(); ++i){
            for(int j = 0; j < triangle[i].size(); ++j){
                if(i == 0)
                    res[i][j] = triangle[i][j];
                else if(j == 0)
                    res[i][j] = res[i-1][j] + triangle[i][j];
                else if(j >= triangle[i-1].size())
                    res[i][j] = res[i-1][j-1] + triangle[i][j];
                else
                    res[i][j] = min(res[i-1][j-1], res[i-1][j]) + triangle[i][j];
                }
            }
        return *min_element(res[triangle.size()-1].begin(), res[triangle.size()-1].end());
    }
};

64. Minimum Path Sum


// 创建一个和输入矩阵同等大小的矩阵res
// res[row][col]存储从左上角到达这个点的最小距离
// res[row][col] = min(grid[row-1][col], grid[row][col-1]) + grid[row][col]
class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if(grid.size() == 0)
            return 0;
        vector<vector<int>> res(grid.size(), vector<int>(grid[0].size(), -1));
        for(int row = 0; row < grid.size(); ++row){
            for(int col = 0; col < grid[0].size(); ++col){
                // min(grid[row-1][col], grid[row][col-1]) + grid[row][col]
                // 处于第一行,第一列
                if(row == 0 && col == 0){
                    res[row][col] = grid[row][col];
                }
                // 第一行,没有上侧元素
                else if(row == 0){
                    res[row][col] = res[row][col-1] + grid[row][col];

                }
                // 第一列,没有左侧元素
                else if(col == 0){
                    res[row][col] = res[row-1][col] + grid[row][col];
                }
                else{
                    res[row][col] = min(res[row-1][col], res[row][col-1]) + grid[row][col];
                }
            }
        }
        return res[grid.size() - 1][grid[0].size() - 1];
    }
};

343. Integer Break


// n = 1 n = 2 n = 3比较特殊,单独考虑
// n >= 4 : f(n) = max(f(n-1)*f(1), f(n-2)*f(2),...,f(1)*f(n-1))
// f(n-1)f(1) 与 f(1)f(n-1)重复计算,算一半就可以了,循环条件j <= i/2即可
class Solution {
public:
    int integerBreak(int n) {
        if(n == 2)
            return 1;
        if(n == 3)
            return 2;
        // n >= 4
        vector<int> res(n+1, -1);
        res[1] = 1; // n = 1
        res[2] = 2; // n = 2
        res[3] = 3; // n = 3
        for(int i = 4; i <= n; ++i){
            int temp = 0;
            for(int j = 1; j <= i/2; ++j){
                temp = max(temp, res[j] * res[i-j]);
            }
            res[i] = temp;
        }
        return res[n];
    }
};

279. Perfect Squares


// 简单的动态规划思想,但leetcode超时了
class Solution {
public:
    int numSquares(int n) {
        if(n < 1)
            return 0;
        vector<int> res(n+1, 0);
        res[0] = 0;
        res[1] = 1;
        for(int i = 2; i <= n; ++i){
            // n本身就是一个完全平方数,不需要拆开,结果直接置为1
            if(int(sqrt(i)) * int(sqrt(i)) == i)
                res[i] = 1;
            else{
                int min_count = INT_MAX;
                // 需要拆成两个数
                for(int j = 1; j <= i/2; ++j){
                    min_count = min(res[j]+res[i-j], min_count);
                }
                res[i] = min_count;
            }    
        }
        return res[n];
    }
};
// 改进一下:
// 通过leetcode
class Solution {
public:
    /* 如果一个数x可以表示为一个任意数a加上一个平方数bxb,也就是x = a + bxb,
     * 那么能组成这个数x最少的平方数个数,就是能组成a最少的平方数个数加上1(因为b*b已经是平方数了)。
     */
    int numSquares(int n) {
        // 将所有非平方数的结果置最大,保证之后比较的时候不被选中
        vector<int> nums(n + 1, INT_MAX);

        // 将所有整平方数的结果置1
        for (int i = 0; i*i <= n; ++i)
            nums[i*i] = 1;

        // 从小到大找任意数a
        for (int a = 0; a <= n; ++a){
            // 从小到大找平方数b*b
            for (int b = 0; a + b*b <= n; ++b){
                // 因为a+b*b可能本身就是平方数,所以我们要取两个中较小的
                nums[a + b*b] = min(nums[a] + 1, nums[a + b*b]);
            }
        }
        return nums[n];
    }
};

91. Decode Ways


// 和青蛙跳台阶很像
// f(n) = f(n-1) + f(n-2)
// 但是多了限制条件,需要检查最后一个或两个数字是否能构成有效的编码
class Solution {
public:
    int numDecodings(string s) {
        if (s.empty())
            return 0;

        vector<int> res(s.size() + 1, 0);

        if (s.size() >= 1 && isValidForOneBit(int(s[0] - '0')))
            res[1] = 1;
        if (s.size() >= 2){
            if (isValidForOneBit(s[0] - '0') && isValidForOneBit(int(s[1] - '0')))
                res[2] += 1;
            if (isValidForTwoBit(atoi(s.substr(0, 2).c_str())))
                res[2] += 1;
        }

        for (int i = 2; i < s.size(); ++i){
            if (isValidForOneBit(int(s[i] - '0')))
                res[i + 1] += res[i];
            if (isValidForTwoBit(atoi(s.substr(i - 1, 2).c_str())))
                res[i + 1] += res[i - 1];
        }

        return res[s.size()];
    }
    bool isValidForOneBit(int n){
        return n >= 1 && n <= 9;
    }
    bool isValidForTwoBit(int n){
        return n >= 10 && n <= 26;
    }
};

62. Unique Paths


// 这题动态规划就很简单了
// res[row][col] += res[row-1][col] + res[row][col-1]
// 注意边界条件即可
class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m <= 0 || n <= 0)
            return 0;
        vector<vector<int>> res(m, vector<int>(n, 0));
        for(int i = 0; i < n; ++i)
            res[0][i] = 1;
        for(int i = 0; i < m; ++i)
            res[i][0] = 1;
        for(int row = 1; row < m; ++row){
            for(int col = 1; col < n; ++col)
                res[row][col] += res[row-1][col] + res[row][col-1];
        }
        return res[m-1][n-1];
    }
};

63. Unique Paths II


// 相比上一题,多了一点点限制条件而已
class Solution {
public:
    int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
        if(obstacleGrid.size() <= 0 || obstacleGrid[0].size() <= 0)
            return 0;
        vector<vector<int>> res(obstacleGrid.size(), vector<int>(obstacleGrid[0].size(), 0));
        if(obstacleGrid[0][0] == 1)
            return 0;
        res[0][0] = 1;
        // 第一行
        for(int col = 1; col < obstacleGrid[0].size(); ++col){
            if(obstacleGrid[0][col] != 1)
                res[0][col] = res[0][col-1];
            else
                res[0][col] = 0;
        }
        // 第一列
        for(int row = 1; row < obstacleGrid.size(); ++row){
            if(obstacleGrid[row][0] != 1)
                res[row][0] = res[row-1][0];
            else
                res[row][0] = 0;
        }
        // 其他
        for(int row = 1; row < obstacleGrid.size(); ++row){
            for(int col = 1; col < obstacleGrid[0].size(); ++col)
                if(obstacleGrid[row][col] != 1)
                    res[row][col] += res[row-1][col] + res[row][col-1];
                else
                    res[row][col] = 0;
        }

        return res[obstacleGrid.size()-1][obstacleGrid[0].size()-1];

    }
};

198. House Robber
213. House Robber II
337. House Robber III
309. Best Time to Buy and Sell Stock with Cooldown








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值