LeetCode—动态规划

LeetCode—动态规划

斐波那契数列
1、爬楼梯
T70. Climbing Stairs (Easy)
LeetCode—动态规划_第1张图片

class Solution {
public:
    int climbStairs(int n) {
        if (n <= 1) return 1;
        vector<int> dp(n);
        dp[0] = 1; dp[1] = 2;
        for (int i = 2; i < n; ++i) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp.back();
        
    }
};

2、强盗抢劫
T198. House Robber (Easy)
LeetCode—动态规划_第2张图片

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
        vector<int> dp = {nums[0], max(nums[0], nums[1])};
        for (int i = 2; i < nums.size(); ++i) {
            dp.push_back(max(nums[i] + dp[i - 2], dp[i - 1]));
        }
        return dp.back();

    }
};

3、强盗在环形街区抢劫
T213. House Robber II (Medium)
LeetCode—动态规划_第3张图片

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
        return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
    }
    int rob(vector<int> &nums, int left, int right) {
        if (right - left <= 1) return nums[left];
        vector<int> dp(right, 0);
        dp[left] = nums[left];
        dp[left + 1] = max(nums[left], nums[left + 1]);
        for (int i = left + 2; i < right; ++i) {
            dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
        }
        return dp.back();

    }
};

4、信件错排
LeetCode—动态规划_第4张图片
5、母牛生产
程序员代码面试指南-P181

矩阵路径

1、矩阵的最小路径和
T64. Minimum Path Sum (Medium)
LeetCode—动态规划_第5张图片

class Solution {
public:
    int minPathSum(vector<vector<int>>& grid) {
        if (grid.empty() || grid[0].empty()) return 0;
        int m = grid.size(), n = grid[0].size();
        vector<vector<int>> dp(m, vector<int>(n));
        dp[0][0] = grid[0][0];
        for (int i = 1; i < m; ++i) dp[i][0] = grid[i][0] + dp[i - 1][0];
        for (int j = 1; j < n; ++j) dp[0][j] = grid[0][j] + dp[0][j - 1];
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) {
                dp[i][j] = grid[i][j] + min(dp[i - 1][j], dp[i][j - 1]);
            }
        }
        return dp[m - 1][n - 1];
        
    }
};

2、矩阵的总路径数
T62. Unique Paths (Medium)
LeetCode—动态规划_第6张图片

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<int> dp(n, 1);
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) {
                dp[j] += dp[j - 1]; 
            }
        }
        return dp[n - 1];
        
    }
};

数组区间

1、数组区间和
T303. Range Sum Query - Immutable (Easy)
LeetCode—动态规划_第7张图片

class NumArray {
public:
    NumArray(vector<int> &nums) {
        dp = nums;
        for (int i = 1; i < nums.size(); ++i) {
            dp[i] += dp[i - 1];
        }
    }
    int sumRange(int i, int j) {
        return i == 0? dp[j] : dp[j] - dp[i - 1];
    }
private:
    vector<int> dp;
};

2、数组中等差递增子区间的个数
T413. Arithmetic Slices (Medium)
LeetCode—动态规划_第8张图片

class Solution {
public:
    int numberOfArithmeticSlices(vector<int>& A) {
        int res = 0, len = 2, n = A.size();
        for (int i = 2; i < n; ++i) {
            if (A[i] - A[i - 1] == A[i - 1] - A[i - 2]) {
                ++len;
            } else {
                if (len > 2) res += (len - 1) * (len - 2) * 0.5;
                len = 2;
            }
        }
        if (len > 2) res += (len - 1) * (len - 2) * 0.5;
        return res;

    }
};

分割整数

1、分割整数的最大乘积
T343. Integer Break (Medim)
LeetCode—动态规划_第9张图片

class Solution {
public:
    int integerBreak(int n) {
        vector<int> dp(n + 1, 1);
        for (int i = 3; i <= n; ++i) {
            for (int j = 1; j < i; ++j) {
                dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]));
            }
        }
        return dp[n];

    }
};

2、按平方数来分割整数
T279. Perfect Squares(Medium)
LeetCode—动态规划_第10张图片

class Solution {
public:
    int numSquares(int n) {
        vector<int> result(n+1, 0x7FFFFFFF); // 每个数的最优解都存在result数组里
    result[0] = 0;
    for (int i = 1; i <= n; i++){
        for(int j = 1; i-j*j >= 0 ; j++) {  // 观察比N小的数,且符合N = IxI + N'的数值
            result[i] = min(result[i], result[i-j*j] + 1); // 把最优解(最小值)+ 1 写入result
        }
    }
    return result[n];


    }
};

3、分割整数构成字母字符串
T91. Decode Ways (Medium)
LeetCode—动态规划_第11张图片

class Solution {
public:
    int numDecodings(string s) {
        if (s.empty() || s[0] == '0') return 0;
        vector<int> dp(s.size() + 1, 0);
        dp[0] = 1;
        for (int i = 1; i < dp.size(); ++i) {
            dp[i] = (s[i - 1] == '0') ? 0 : dp[i - 1];
            if (i > 1 && (s[i - 2] == '1' || (s[i - 2] == '2' && s[i - 1] <= '6'))) {
                dp[i] += dp[i - 2];
            }
        }
        return dp.back();
        
    }
};

最长递增子序列

1、最长递增子序列
T300. Longest Increasing Subsequence (Medium)
LeetCode—动态规划_第12张图片

class Solution {
public:
    int lengthOfLIS(vector<int>& nums) {
        vector<int> dp(nums.size(), 1);
        int res = 0;
        for (int i = 0; i < nums.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (nums[i] > nums[j]) {
                    dp[i] = max(dp[i], dp[j] + 1);
                }
            }
            res = max(res, dp[i]);
        }
        return res;

    }
};

2、一组整数对能够构成的最长链
T646. Maximum Length of Pair Chain (Medium)
LeetCode—动态规划_第13张图片

class Solution {
public:
    int findLongestChain(vector<vector<int>>& pairs) {
        stack<vector<int>> st;
        sort(pairs.begin(), pairs.end(), [](vector<int>& a, vector<int>& b) {
            return a[1] < b[1];
        });
        for (auto pair : pairs) {
            if (st.empty()) st.push(pair);
            else {
                auto t = st.top();
                if (pair[0] > t[1]) st.push(pair);
            }
        }
        return st.size();

    }
};

3、最长摆动子序列
T376. Wiggle Subsequence (Medium)
LeetCode—动态规划_第14张图片

class Solution {
public:
    int wiggleMaxLength(vector<int>& nums) {
        if (nums.empty()) return 0;
        vector<int> p(nums.size(), 1);
        vector<int> q(nums.size(), 1);
        for (int i = 1; i < nums.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (nums[i] > nums[j]) p[i] = max(p[i], q[j] + 1);
                else if (nums[i] < nums[j]) q[i] = max(q[i], p[j] + 1);
            }
        }
        return max(p.back(), q.back());

    }
};

最长公共子序列

1、最长公共子序列
T1143. Longest Common Subsequence
LeetCode—动态规划_第15张图片

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int n=text1.size(),m=text2.size();
	int dp[m+1],last=0,temp;
	fill(dp,dp+m+1,0);
        for(int i=1;i<=n;++i,last=0){
		for(int j=1;j<=m;++j){
            	   temp=dp[j];
		   if(text1[i-1]==text2[j-1])	dp[j]=last+1; 
		   else	 dp[j]=max(dp[j],dp[j-1]);
        	   last=temp;
		}
        }
	return dp[m];

    }
};

0-1 背包

1、划分数组为和相等的两部分
T416. Partition Equal Subset Sum (Medium)
LeetCode—动态规划_第16张图片

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        int sum = accumulate(nums.begin(), nums.end(), 0), target = sum >> 1;
        if (sum & 1) return false;
        vector<bool> dp(target + 1, false);
        dp[0] = true;
        for (int num : nums) {
            for (int i = target; i >= num; --i) {
                dp[i] = dp[i] || dp[i - num];
            }
        }
        return dp[target];

    }
};

2、改变一组数的正负号使得它们的和为一给定数
T494. Target Sum (Medium)
LeetCode—动态规划_第17张图片

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int S) {
        int res = 0;
        helper(nums, S, 0, res);
        return res;
    }
    void helper(vector<int>& nums, long S, int start, int& res) {
        if (start >= nums.size()) {
            if (S == 0) ++res;
            return;
        }
        helper(nums, S - nums[start], start + 1, res);
        helper(nums, S + nums[start], start + 1, res);

    }
};

3、01 字符构成最多的字符串
T474. Ones and Zeroes (Medium)
LeetCode—动态规划_第18张图片

class Solution {
public:
    int findMaxForm(vector<string>& strs, int m, int n) {
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (string str : strs) {
            int zeros = 0, ones = 0;
            for (char c : str) (c == '0') ? ++zeros : ++ones;
            for (int i = m; i >= zeros; --i) {
                for (int j = n; j >= ones; --j) {
                    dp[i][j] = max(dp[i][j], dp[i - zeros][j - ones] + 1);
                }
            }
        }
        return dp[m][n];

    }
};

4、找零钱的最少硬币数
T322. Coin Change (Medium)
LeetCode—动态规划_第19张图片

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
         vector<int> dp(amount + 1, amount + 1);
        dp[0] = 0;
        for (int i = 1; i <= amount; ++i) {
            for (int j = 0; j < coins.size(); ++j) {
                if (coins[j] <= i) {
                    dp[i] = min(dp[i], dp[i - coins[j]] + 1);
                }
            }
        }
        return (dp[amount] > amount) ? -1 : dp[amount];

    }
};

5、找零钱的硬币数组合
T518. Coin Change 2 (Medium)
LeetCode—动态规划_第20张图片

class Solution {
public:
    int change(int amount, vector<int>& coins) {
        vector<vector<int>> dp(coins.size() + 1, vector<int>(amount + 1, 0));
        dp[0][0] = 1;
        for (int i = 1; i <= coins.size(); ++i) {
            dp[i][0] = 1;
            for (int j = 1; j <= amount; ++j) {
                dp[i][j] = dp[i - 1][j] + (j >= coins[i - 1] ? dp[i][j - coins[i - 1]] : 0);
            }
        }
        return dp[coins.size()][amount];

    }
};

6、字符串按单词列表分割
T139. Word Break (Medium)
LeetCode—动态规划_第21张图片

class Solution {
public:
    bool wordBreak(string s, vector<string>& wordDict) {
        unordered_set<string> wordSet(wordDict.begin(), wordDict.end());
        vector<bool> dp(s.size() + 1);
        dp[0] = true;
        for (int i = 0; i < dp.size(); ++i) {
            for (int j = 0; j < i; ++j) {
                if (dp[j] && wordSet.count(s.substr(j, i - j))) {
                    dp[i] = true;
                    break;
                }
            }
        }
        return dp.back();

    }
};

7、组合总和
T377. Combination Sum IV (Medium)
LeetCode—动态规划_第22张图片

class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        vector<int> dp(target + 1, 0);
    dp[0] = 1;
    for (int i = 0; i <= target; i++) {
        for (int j = 0; j < nums.size(); j++) {
            if (i < nums[j]) continue;
            dp[i] = (dp[i] >= INT_MAX - dp[i - nums[j]]) ? INT_MAX : dp[i] + dp[i - nums[j]];
        }
    }
    return dp[target];

    }
};

股票交易

1、需要冷却期的股票交易
T309. Best Time to Buy and Sell Stock with Cooldown(Medium)
LeetCode—动态规划_第23张图片

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int buy = INT_MIN, pre_buy = 0, sell = 0, pre_sell = 0;
        for (int price : prices) {
            pre_buy = buy;
            buy = max(pre_sell - price, pre_buy);
            pre_sell = sell;
            sell = max(pre_buy + price, pre_sell);
        }
        return sell;

    }
};

2、需要交易费用的股票交易
T714. Best Time to Buy and Sell Stock with Transaction Fee (Medium)
LeetCode—动态规划_第24张图片

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        vector<int> sold(prices.size(), 0), hold = sold;
        hold[0] = -prices[0];
        for (int i = 1; i < prices.size(); ++i) {
            sold[i] = max(sold[i - 1], hold[i - 1] + prices[i] - fee);
            hold[i] = max(hold[i - 1], sold[i - 1] - prices[i]);
        }
        return sold.back();

    }
};

3、只能进行两次的股票交易
T123. Best Time to Buy and Sell Stock III (Hard)
LeetCode—动态规划_第25张图片

class Solution {
public:
    int maxProfit(vector<int>& prices) {
                if(prices.size()==0) return 0;
        int *dp=new int[prices.size()];
        int *dp_2=new int[prices.size()];
        int ans=0;
        left(prices,dp);
        right(prices,dp_2);
        for(int i=0;i<prices.size();i++)
            ans=max(ans,dp[i]+dp_2[i]);
        return ans;

    }

    void left( vector<int> prices, int *&dp)
    {
        int ans=0;
        int low=prices[0];
        for(int i=0;i<prices.size();i++)
        {
            ans=max(ans,prices[i]-low);
            dp[i]=ans;
            low=min(low,prices[i]);
        }
    }
    void right(vector<int> prices,int *&dp)
    {
        int ans=0;
        int high=prices[prices.size()-1];
        for(int i=prices.size()-1;i>=0;i--)
        {
            ans=max(ans,high-prices[i]);
            dp[i]=ans;
            high=max(high,prices[i]);
        }
    }

};

4、只能进行 k 次的股票交易
T188. Best Time to Buy and Sell Stock IV (Hard)
LeetCode—动态规划_第26张图片

class Solution {
public:
    int maxProfit(int k, vector<int>& prices) {
        if (prices.size() <= 1) return 0;
        //std::vector> dp(k+1, {-prices[0], 0});
        // 这里有一个隐藏很深的 bug, 就如果 k 的值很大, 就会直接把栈爆掉!!
        // 所以应该按照 k 值做优化, 将 vector 声明在 if 语句内部
        if (k < prices.size() / 2)  {
                std::vector<std::pair<int, int>> dp(k+1, {-prices[0], 0});
                for(int i=1;i<prices.size();i++)
                {
                    for(int j=1; j < k+1; j++)
                    {
                        int hold = std::max(dp[j].first, dp[j-1].second-prices[i]);
                        int not_hold = std::max(dp[j].second, dp[j].first+prices[i]);
                        dp[j].first = hold; dp[j].second = not_hold;
                    }
                }
            return dp[k].second; //max(dp[k].first, dp[k].second);
        } else  {
            std::pair<int, int> dp = {-prices[0], 0};
            for (int i=1; i<prices.size(); i++) {
                int hold = std::max(dp.first, dp.second-prices[i]);
                int not_hold = std::max(dp.second, dp.first+prices[i]);
                dp.first = hold; dp.second = not_hold;
            }
            return dp.second;
        }
    }

    
};

字符串编辑

1、删除两个字符串的字符使它们相等
T583. Delete Operation for Two Strings (Medium)
LeetCode—动态规划_第27张图片

class Solution {
public:
    int minDistance(string word1, string word2) {
         int n1 = word1.size(), n2 = word2.size();
        vector<vector<int>> dp(n1 + 1, vector<int>(n2 + 1, 0));
        for (int i = 1; i <= n1; ++i) {
            for (int j = 1; j <= n2; ++j) {
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return n1 + n2 - 2 * dp[n1][n2];

    }
};

2、编辑距离
T72. Edit Distance (Hard)
LeetCode—动态规划_第28张图片

class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word1.size(), n = word2.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1));
        for (int i = 0; i <= m; ++i) dp[i][0] = i;
        for (int i = 0; i <= n; ++i) dp[0][i] = i;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (word1[i - 1] == word2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j], dp[i][j - 1])) + 1;
                }
            }
        }
        return dp[m][n];
        
    }
};

3、复制粘贴字符
T650. 2 Keys Keyboard (Medium)
LeetCode—动态规划_第29张图片

class Solution {
public:
    int minSteps(int n) {
        if (n == 1) return 0;
        int res = n;
        for (int i = n - 1; i > 1; --i) {
            if (n % i == 0) {
                res = min(res, minSteps(n / i) + i);
            }
        }
        return res;

    }
};

你可能感兴趣的:(leetcode刷题)