1. 程式人生 > >leetcode之DP總結

leetcode之DP總結

leetcode之DP總結

2017年07月29日 22:51:39 svdalv 閱讀數:357

版權宣告:本文為博主原創文章,未經博主允許不得轉載。 https://blog.csdn.net/ns708865818/article/details/76266896

303. Range Sum Query - Immutable

解題思路:給定一個數組,計算給定區間的數字的和。利用DP算出從開始處到i的和,dp[i]=sum[i],程式碼如下:

 

 
  1. class NumArray {

  2. public:

  3. NumArray(vector<int> nums)

  4. {

  5. sum.push_back(0);

  6. for(int i=0;i<nums.size();i++)

  7. {

  8. sum.push_back(nums[i]+sum.back());

  9. }

  10.  
  11. }

  12.  
  13. int sumRange(int i, int j)

  14. {

  15. return sum[j+1]-sum[i];

  16.  
  17. }

  18. private:

  19. vector<int> sum;

  20. };

  21.  
  22. /**

  23. * Your NumArray object will be instantiated and called as such:

  24. * NumArray obj = new NumArray(nums);

  25. * int param_1 = obj.sumRange(i,j);

  26. */

53. Maximum Subarray

 

題目描述:求給定陣列的和最大的連續子陣列。

思路一:DP,表示到該元素的時候的和最大的連續子陣列,程式碼如下:

 

 
  1. class Solution {

  2. public:

  3. int maxSubArray(vector<int>& nums)

  4. {

  5. int ret=nums[0];

  6. vector<int> dp(nums.size()+1);

  7. dp[0]=ret;

  8. for(int i=1;i<nums.size();i++)

  9. {

  10. dp[i]=max(dp[i-1]+nums[i],nums[i]);

  11. if(dp[i]>ret)

  12. {

  13. ret=dp[i];

  14. }

  15. }

  16. return ret;

  17.  
  18.  
  19. }

  20. };

思路2:不用DP,不需要額外這麼多記憶體,只用兩個變量表示即可,程式碼如下:

 

 

 
  1. class Solution {

  2. public:

  3. int maxSubArray(vector<int>& nums)

  4. {

  5. int ret=INT_MIN;

  6. int f=0;

  7. for(int i=0;i<nums.size();i++)

  8. {

  9. f=max(nums[i],f+nums[i]);

  10. ret=max(ret,f);

  11. }

  12. return ret;

  13. }

  14. };

198. House Robber
題目描述:給很多房子,每個房子有錢,不能同時偷相鄰的房子的財物,求可能獲得的最多的寶貝。

 

解題思路:DP。遞推公式,我們維護一個一位陣列dp,其中dp[i]表示到i位置時不相鄰數能形成的最大和,dp[i] = max(num[i] + dp[i - 2], dp[i - 1]),程式碼如下:

 

 
  1. class Solution {

  2. public:

  3. int rob(vector<int>& nums)

  4. {

  5. int n=nums.size();

  6. if(n==0)

  7. {

  8. return 0;

  9. }

  10. vector<int> dp(n,0);

  11. dp[0]=nums[0];

  12. dp[1]=max(nums[0],nums[1]);

  13. for(int i=2;i<n;i++)

  14. {

  15. dp[i]=max(dp[i-1],dp[i-2]+nums[i]);

  16. }

  17. return dp[n-1];

  18. }

  19. };

213. House Robber II

 

題目描述:跟上一個題目相比,這裡的房子成一個圈,不能同時包含第一個和最後一個。程式碼如下:

 

 
  1. // DP

  2. class Solution {

  3. public:

  4. int rob(vector<int>& nums)

  5. {

  6. if (nums.size() <= 1)

  7. {

  8. return nums.empty() ? 0 : nums[0];

  9. }

  10. return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));

  11. }

  12. int rob(vector<int> &nums, int left, int right)

  13. {

  14. if (right - left <= 1)

  15. return nums[left];

  16. vector<int> dp(right, 0);

  17. dp[left] = nums[left];

  18. dp[left + 1] = max(nums[left], nums[left + 1]);

  19. for (int i = left + 2; i < right; ++i)

  20. {

  21. dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);

  22. }

  23. return dp.back();

  24. }

  25. };


337. House Robber III

 

題目描述:這個題目擴充套件為二叉樹,即不能同時偷直接相鄰的節點。

Solution1:二叉樹的題目:遞迴,深度優先遍歷,寬度優先遍歷,第一種,遞迴演算法

 

 
  1. /**

  2. * Definition for a binary tree node.

  3. * struct TreeNode {

  4. * int val;

  5. * TreeNode *left;

  6. * TreeNode *right;

  7. * TreeNode(int x) : val(x), left(NULL), right(NULL) {}

  8. * };

  9. */

  10. class Solution {

  11. public:

  12. int rob(TreeNode* root)

  13. {

  14. if(root==NULL)

  15. {

  16. return 0;

  17. }

  18. int val=0;

  19. if(root->left)

  20. {

  21. val=val+rob(root->left->left)+rob(root->left->right);

  22.  
  23. }

  24. if(root->right)

  25. {

  26. val=val+rob(root->right->left)+rob(root->right->right);

  27. }

  28. return max(root->val+val,rob(root->left)+rob(root->right));

  29.  
  30. }

  31. };

Solution 2:用hash來儲存每一個節點對應的最大值。程式碼如下:

 

 

 
  1. class Solution {

  2. public:

  3. int rob(TreeNode* root)

  4. {

  5. unordered_map<TreeNode*, int> m;

  6. return dfs(root, m);

  7. }

  8. int dfs(TreeNode *root, unordered_map<TreeNode*, int> &m)

  9. {

  10. if (!root) return 0;

  11. if (m.count(root)) return m[root];

  12. int val = 0;

  13. if (root->left)

  14. {

  15. val += dfs(root->left->left, m) + dfs(root->left->right, m);

  16. }

  17. if (root->right)

  18. {

  19. val += dfs(root->right->left, m) + dfs(root->right->right, m);

  20. }

  21. val = max(val + root->val, dfs(root->left, m) + dfs(root->right, m));

  22. m[root] = val;

  23. return val;

  24. }

  25. };

338. Counting Bits
題目描述:給定一個數字N,求從0到N的每個數字二進位制表示後1的個數。

 

解題思路:如果一個數為偶數,那麼它包含的1的個數與其除2後的1的個數相同,比如8,4,2,1,如果一個數為奇數,它包含的1的個數等於除2後的數加1,找到相互關係後,程式碼如下:

程式碼:

 

 
  1. class Solution {

  2. public:

  3. vector<int> countBits(int num)

  4. {

  5. vector<int> dp(num+1,0);

  6. dp[1]=1;

  7. for(int i=2;i<num+1;i++)

  8. {

  9. if(i%2==0)

  10. {

  11. dp[i]=dp[i/2];

  12. }

  13. else

  14. {

  15. dp[i]=dp[i/2]+1;

  16. }

  17. }

  18. return dp;

  19.  
  20.  
  21. }

  22. };

647. Palindromic Substrings

 

題目描述:給定一個字串,求該字串的所有對稱的子串。

解題思路:二維DP問題,DP[j][i]表示子串sub(j,i)是否是對稱的子串,如果dp[j][i]=dp[j+1][i-1]+s[i]==s[j].然後統計所有的對稱的子串的個數,程式碼如下:

 

 
  1. class Solution {

  2. public:

  3. int countSubstrings(string s)

  4. {

  5. if(s.size()<=1)

  6. {

  7. return s.size();

  8. }

  9. int n=s.size();

  10. vector<vector<bool>> dp(n,vector<bool>(n,false));

  11. for(int i=0;i<n;i++)

  12. {

  13. for(int j=0;j<i;j++)

  14. {

  15. dp[j][i]=s[j]==s[i]&&((i-j<2)||dp[j+1][i-1])

  16. }

  17. dp[i][i]=true;

  18. }

  19. int ret=0;

  20. for(int i=0;i<n;i++)

  21. {

  22. for(int j=0;j<n;j++)

  23. {

  24. if(dp[i][j])

  25. {

  26. ret++;

  27. }

  28. }

  29. }

  30. return ret;

  31. }

  32. };

5. Longest Palindromic Substring
題目描述:求字串的最長的對稱的子串

 

解題思路:同上

程式碼如下:

 

 
  1. // DP

  2. class Solution {

  3. public:

  4. string longestPalindrome(string s)

  5. {

  6. int dp[s.size()][s.size()] = {0}, left = 0, right = 0, len = 0;

  7. for (int i = 0; i < s.size(); ++i) {

  8. for (int j = 0; j < i; ++j)

  9. {

  10. dp[j][i] = (s[i] == s[j] && (i - j < 2 || dp[j + 1][i - 1]));

  11. if (dp[j][i] && len < i - j + 1)

  12. {

  13. len = i - j + 1;

  14. left = j;

  15. right = i;

  16. }

  17. }

  18. dp[i][i] = 1;

  19. }

  20. return s.substr(left, right - left + 1);

  21. }

  22. };


516. Longest Palindromic Subsequence

 

題目描述:求最長的對稱的子序列。

解題思路:動態規劃

程式碼如下:

 

 
  1. class Solution {

  2. public:

  3. int longestPalindromeSubseq(string s)

  4. {

  5. int n=s.size();

  6. if(n<=1)

  7. {

  8. return n;

  9. }

  10. vector<vector<int>> dp(n,vector<int>(n,0));

  11. for(int i=0;i<n;i++)

  12. {

  13. dp[i][i]=1;

  14. for(int j=i-1;j>=0;j--)

  15. {

  16. if(s[i]==s[j])

  17. {

  18. dp[j][i]=dp[j+1][i-1]+2;

  19. }

  20. else

  21. {

  22. dp[j][i]=max(dp[j+1][i],dp[j][i-1]);

  23. }

  24. }

  25.  
  26. }

  27. return dp[0][n-1];

  28.  
  29. }

  30. };

413. Arithmetic Slices
題目描述:求一個數組的所有的等差數列的子陣列

 

解題思路:DP

 

 
  1. class Solution {

  2. public:

  3. int numberOfArithmeticSlices(vector<int>& A)

  4. {

  5. int res = 0, n = A.size();

  6. vector<int> dp(n, 0);

  7. for (int i = 2; i < n; ++i)

  8. {

  9. if (A[i] - A[i - 1] == A[i - 1] - A[i - 2])

  10. {

  11. dp[i] = dp[i - 1] + 1;

  12. }

  13. res += dp[i];

  14. }

  15. return res;

  16. }

  17. };

343. Integer Break

題目描述:給定一個數字,將該數字至少分成兩個,求分開後乘積最大的結果。

解題思路:dp,試著寫前幾個,發現規律。

 
  1. class Solution {

  2. public:

  3. int integerBreak(int n)

  4. {

  5. vector<int>dp(7);

  6. dp[0]=0;

  7. dp[1]=0;

  8. dp[2]=1;

  9. dp[3]=2;

  10. dp[4]=4;

  11. dp[5]=6;

  12. dp[6]=9;

  13. for (int i = 7; i <= n; ++i)

  14. {

  15. dp.push_back(dp[i-3]*3);

  16. }

  17. return dp[n];

  18. }

  19. };


646. Maximum Length of Pair Chain

 

題目描述:給定一個區間陣列,求滿足要求的最長長度。

Input: [[1,2], [2,3], [3,4]]
Output: 2
Explanation: The longest chain is [1,2] -> [3,4]

 

解題思路:按照結束值進行排序,即可。

程式碼:

 

 
  1. class Solution {

  2. public:

  3. int findLongestChain(vector<vector<int>>& pairs)

  4. {

  5. sort(pairs.begin(),pairs.end(),cmp);

  6. vector<int> pair;

  7. int ret=0;

  8. for(int i=0;i<pairs.size();i++)

  9. {

  10. if(i==0||pairs[i][0]>pair[1])

  11. {

  12. pair=pairs[i];

  13. ret++;

  14. }

  15. }

  16. return ret;

  17.  
  18. }

  19. static bool cmp(vector<int> a,vector<int> b)

  20. {

  21. return a[1]<b[1]||a[1]==b[1]&&a[0]<b[0];

  22. }

 392. Is Subsequence

題目描述:給定兩個字串s和t,判斷s是不是t的子串。

解題思路:依次遍歷即可;

程式碼:

 

 
  1. class Solution {

  2. public:

  3. bool isSubsequence(string s, string t)

  4. {

  5. int m=s.size();

  6. int n=t.size();

  7. if(m>n)

  8. {

  9. return false;

  10. }

  11. if(m==n)

  12. {

  13. return s==t;

  14. }

  15. int i=0;

  16. int j=0;

  17. while(i<m&&j<n)

  18. {

  19. if(s[i]==t[j])

  20. {

  21. i++;

  22. j++;

  23. }

  24. else

  25. {

  26. j++;

  27. }

  28. }

  29. if(i==m)

  30. {

  31. return true;

  32. }

  33. return false;

  34.  
  35. }

  36. };

494. Target Sum
題目描述:給定一個數組,求能夠滿足給定和的組合的個數。

 

Input: nums is [1, 1, 1, 1, 1], S is 3. 
Output: 5
Explanation: 

-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

There are 5 ways to assign symbols to make the sum of nums be target 3.

解題思路:深度優先遍歷,求每一種組合的結果,然後統計滿足要求的結果的個數。

 

程式碼如下:

 

 
  1. class Solution {

  2. public:

  3. int findTargetSumWays(vector<int>& nums, int S)

  4. {

  5. return help(nums,0,S);

  6. }

  7. int help(vector<int>&nums,int start,int S)

  8. {

  9. if(start>=nums.size())

  10. {

  11. if(S==0)

  12. {

  13. return 1;

  14. }

  15. return 0;

  16. }

  17. return help(nums,start+1,S-nums[start])+help(nums,start+1,S+nums[start]);

  18. }

  19. };