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],程式碼如下:
-
class NumArray {
-
public:
-
NumArray(vector<int> nums)
-
{
-
sum.push_back(0);
-
for(int i=0;i<nums.size();i++)
-
{
-
sum.push_back(nums[i]+sum.back());
-
}
-
}
-
int sumRange(int i, int j)
-
{
-
return sum[j+1]-sum[i];
-
}
-
private:
-
vector<int> sum;
-
};
-
/**
-
* Your NumArray object will be instantiated and called as such:
-
* NumArray obj = new NumArray(nums);
-
* int param_1 = obj.sumRange(i,j);
-
*/
題目描述:求給定陣列的和最大的連續子陣列。
思路一:DP,表示到該元素的時候的和最大的連續子陣列,程式碼如下:
-
class Solution {
-
public:
-
int maxSubArray(vector<int>& nums)
-
{
-
int ret=nums[0];
-
vector<int> dp(nums.size()+1);
-
dp[0]=ret;
-
for(int i=1;i<nums.size();i++)
-
{
-
dp[i]=max(dp[i-1]+nums[i],nums[i]);
-
if(dp[i]>ret)
-
{
-
ret=dp[i];
-
}
-
}
-
return ret;
-
}
-
};
思路2:不用DP,不需要額外這麼多記憶體,只用兩個變量表示即可,程式碼如下:
-
class Solution {
-
public:
-
int maxSubArray(vector<int>& nums)
-
{
-
int ret=INT_MIN;
-
int f=0;
-
for(int i=0;i<nums.size();i++)
-
{
-
f=max(nums[i],f+nums[i]);
-
ret=max(ret,f);
-
}
-
return ret;
-
}
-
};
198. House Robber
題目描述:給很多房子,每個房子有錢,不能同時偷相鄰的房子的財物,求可能獲得的最多的寶貝。
解題思路:DP。遞推公式,我們維護一個一位陣列dp,其中dp[i]表示到i位置時不相鄰數能形成的最大和,dp[i] = max(num[i] + dp[i - 2], dp[i - 1]),程式碼如下:
-
class Solution {
-
public:
-
int rob(vector<int>& nums)
-
{
-
int n=nums.size();
-
if(n==0)
-
{
-
return 0;
-
}
-
vector<int> dp(n,0);
-
dp[0]=nums[0];
-
dp[1]=max(nums[0],nums[1]);
-
for(int i=2;i<n;i++)
-
{
-
dp[i]=max(dp[i-1],dp[i-2]+nums[i]);
-
}
-
return dp[n-1];
-
}
-
};
題目描述:跟上一個題目相比,這裡的房子成一個圈,不能同時包含第一個和最後一個。程式碼如下:
-
// DP
-
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();
-
}
-
};
題目描述:這個題目擴充套件為二叉樹,即不能同時偷直接相鄰的節點。
Solution1:二叉樹的題目:遞迴,深度優先遍歷,寬度優先遍歷,第一種,遞迴演算法
-
/**
-
* 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==NULL)
-
{
-
return 0;
-
}
-
int val=0;
-
if(root->left)
-
{
-
val=val+rob(root->left->left)+rob(root->left->right);
-
}
-
if(root->right)
-
{
-
val=val+rob(root->right->left)+rob(root->right->right);
-
}
-
return max(root->val+val,rob(root->left)+rob(root->right));
-
}
-
};
Solution 2:用hash來儲存每一個節點對應的最大值。程式碼如下:
-
class Solution {
-
public:
-
int rob(TreeNode* root)
-
{
-
unordered_map<TreeNode*, int> m;
-
return dfs(root, m);
-
}
-
int dfs(TreeNode *root, unordered_map<TreeNode*, int> &m)
-
{
-
if (!root) return 0;
-
if (m.count(root)) return m[root];
-
int val = 0;
-
if (root->left)
-
{
-
val += dfs(root->left->left, m) + dfs(root->left->right, m);
-
}
-
if (root->right)
-
{
-
val += dfs(root->right->left, m) + dfs(root->right->right, m);
-
}
-
val = max(val + root->val, dfs(root->left, m) + dfs(root->right, m));
-
m[root] = val;
-
return val;
-
}
-
};
338. Counting Bits
題目描述:給定一個數字N,求從0到N的每個數字二進位制表示後1的個數。
解題思路:如果一個數為偶數,那麼它包含的1的個數與其除2後的1的個數相同,比如8,4,2,1,如果一個數為奇數,它包含的1的個數等於除2後的數加1,找到相互關係後,程式碼如下:
程式碼:
-
class Solution {
-
public:
-
vector<int> countBits(int num)
-
{
-
vector<int> dp(num+1,0);
-
dp[1]=1;
-
for(int i=2;i<num+1;i++)
-
{
-
if(i%2==0)
-
{
-
dp[i]=dp[i/2];
-
}
-
else
-
{
-
dp[i]=dp[i/2]+1;
-
}
-
}
-
return dp;
-
}
-
};
題目描述:給定一個字串,求該字串的所有對稱的子串。
解題思路:二維DP問題,DP[j][i]表示子串sub(j,i)是否是對稱的子串,如果dp[j][i]=dp[j+1][i-1]+s[i]==s[j].然後統計所有的對稱的子串的個數,程式碼如下:
-
class Solution {
-
public:
-
int countSubstrings(string s)
-
{
-
if(s.size()<=1)
-
{
-
return s.size();
-
}
-
int n=s.size();
-
vector<vector<bool>> dp(n,vector<bool>(n,false));
-
for(int i=0;i<n;i++)
-
{
-
for(int j=0;j<i;j++)
-
{
-
dp[j][i]=s[j]==s[i]&&((i-j<2)||dp[j+1][i-1])
-
}
-
dp[i][i]=true;
-
}
-
int ret=0;
-
for(int i=0;i<n;i++)
-
{
-
for(int j=0;j<n;j++)
-
{
-
if(dp[i][j])
-
{
-
ret++;
-
}
-
}
-
}
-
return ret;
-
}
-
};
5. Longest Palindromic Substring
題目描述:求字串的最長的對稱的子串
解題思路:同上
程式碼如下:
-
// DP
-
class Solution {
-
public:
-
string longestPalindrome(string s)
-
{
-
int dp[s.size()][s.size()] = {0}, left = 0, right = 0, len = 0;
-
for (int i = 0; i < s.size(); ++i) {
-
for (int j = 0; j < i; ++j)
-
{
-
dp[j][i] = (s[i] == s[j] && (i - j < 2 || dp[j + 1][i - 1]));
-
if (dp[j][i] && len < i - j + 1)
-
{
-
len = i - j + 1;
-
left = j;
-
right = i;
-
}
-
}
-
dp[i][i] = 1;
-
}
-
return s.substr(left, right - left + 1);
-
}
-
};
516. Longest Palindromic Subsequence
題目描述:求最長的對稱的子序列。
解題思路:動態規劃
程式碼如下:
-
class Solution {
-
public:
-
int longestPalindromeSubseq(string s)
-
{
-
int n=s.size();
-
if(n<=1)
-
{
-
return n;
-
}
-
vector<vector<int>> dp(n,vector<int>(n,0));
-
for(int i=0;i<n;i++)
-
{
-
dp[i][i]=1;
-
for(int j=i-1;j>=0;j--)
-
{
-
if(s[i]==s[j])
-
{
-
dp[j][i]=dp[j+1][i-1]+2;
-
}
-
else
-
{
-
dp[j][i]=max(dp[j+1][i],dp[j][i-1]);
-
}
-
}
-
}
-
return dp[0][n-1];
-
}
-
};
413. Arithmetic Slices
題目描述:求一個數組的所有的等差數列的子陣列
解題思路:DP
-
class Solution {
-
public:
-
int numberOfArithmeticSlices(vector<int>& A)
-
{
-
int res = 0, n = A.size();
-
vector<int> dp(n, 0);
-
for (int i = 2; i < n; ++i)
-
{
-
if (A[i] - A[i - 1] == A[i - 1] - A[i - 2])
-
{
-
dp[i] = dp[i - 1] + 1;
-
}
-
res += dp[i];
-
}
-
return res;
-
}
-
};
題目描述:給定一個數字,將該數字至少分成兩個,求分開後乘積最大的結果。
解題思路:dp,試著寫前幾個,發現規律。
-
class Solution {
-
public:
-
int integerBreak(int n)
-
{
-
vector<int>dp(7);
-
dp[0]=0;
-
dp[1]=0;
-
dp[2]=1;
-
dp[3]=2;
-
dp[4]=4;
-
dp[5]=6;
-
dp[6]=9;
-
for (int i = 7; i <= n; ++i)
-
{
-
dp.push_back(dp[i-3]*3);
-
}
-
return dp[n];
-
}
-
};
646. Maximum Length of Pair Chain
題目描述:給定一個區間陣列,求滿足要求的最長長度。
Input: [[1,2], [2,3], [3,4]] Output: 2 Explanation: The longest chain is [1,2] -> [3,4]
解題思路:按照結束值進行排序,即可。
程式碼:
-
class Solution {
-
public:
-
int findLongestChain(vector<vector<int>>& pairs)
-
{
-
sort(pairs.begin(),pairs.end(),cmp);
-
vector<int> pair;
-
int ret=0;
-
for(int i=0;i<pairs.size();i++)
-
{
-
if(i==0||pairs[i][0]>pair[1])
-
{
-
pair=pairs[i];
-
ret++;
-
}
-
}
-
return ret;
-
}
-
static bool cmp(vector<int> a,vector<int> b)
-
{
-
return a[1]<b[1]||a[1]==b[1]&&a[0]<b[0];
-
}
392. Is Subsequence
題目描述:給定兩個字串s和t,判斷s是不是t的子串。
解題思路:依次遍歷即可;
程式碼:
-
class Solution {
-
public:
-
bool isSubsequence(string s, string t)
-
{
-
int m=s.size();
-
int n=t.size();
-
if(m>n)
-
{
-
return false;
-
}
-
if(m==n)
-
{
-
return s==t;
-
}
-
int i=0;
-
int j=0;
-
while(i<m&&j<n)
-
{
-
if(s[i]==t[j])
-
{
-
i++;
-
j++;
-
}
-
else
-
{
-
j++;
-
}
-
}
-
if(i==m)
-
{
-
return true;
-
}
-
return false;
-
}
-
};
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.
解題思路:深度優先遍歷,求每一種組合的結果,然後統計滿足要求的結果的個數。
程式碼如下:
-
class Solution {
-
public:
-
int findTargetSumWays(vector<int>& nums, int S)
-
{
-
return help(nums,0,S);
-
}
-
int help(vector<int>&nums,int start,int S)
-
{
-
if(start>=nums.size())
-
{
-
if(S==0)
-
{
-
return 1;
-
}
-
return 0;
-
}
-
return help(nums,start+1,S-nums[start])+help(nums,start+1,S+nums[start]);
-
}
-
};