121.Best Time to Buy and Sell Stock
思路:遍历数组,找到当前位置之前最小的数,然后选择当前买入差值和之前最大值之间的最大值。
int maxProfit(vector& prices) {
int res = 0,buy = INT_MAX;
for (int price : prices) {
buy = min(buy,price);
res = max(res,price - buy);
}
return res;
}
746.Min Cost Climbing Stairs
思路:从第二个台阶开始,计算到达该台阶最小的cost,因为第i个台阶,和i-1和i-2有关,则计算cost[i]
int minCostClimbingStairs(vector& cost) {
int n = cost.size();
vector dp(n,0);
dp[0] = cost[0];
dp[1] = cost[1];
for (int i = 2; i < n; i++) {
dp[i] = cost[i] + min(dp[i-1],dp[i-2]);
}
return min(dp[n-1],dp[n-2]);
}
思路2:因为我们只关注i-1和i-2的值,所以没必要保存所有台阶的值,只需要保存i-1和i-2.
int minCostClimbingStairs(vector& cost) {
int n = cost.size();
int a = cost[0];
int b = cost[1];
int t;
for (int i = 2; i < n; i++) {
t = cost[i] + min(a,b);
a = b;
b = t;
}
return min(t,a);
}
int climbStairs(int n) {
int a = 1,b = 2;
int res = 0;
if (n == 1)
return 1;
if (n == 2)
return 2;
for (int i = 3; i <= n; i++) {
res = a + b;
a = b;
b = res;
}
return res;
}
int maxSubArray(vector& nums) {
int res = INT_MIN;
int curSum = 0;
for (int num : nums) {
curSum = max(num,curSum + num);//换句话就是,如果cursum为负,那么最大值就是num
res = max(curSum,res);
}
return res;
}
int rob(vector& nums) {
if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
if (nums.size() == 2) return max(nums[0],nums[1]);
int a = nums[0];
int b = max(a,nums[1]);
int res = 0;
for (int i = 2; i < nums.size(); i++) {
res = max(a + nums[i],b);
a = b;
b = res;
}
return max(res,a);
}
public:
NumArray(vector nums) {
dp.resize(nums.size()+1,0);
for (int i = 1;i < nums.size() + 1; i++) {
dp[i] = dp[i-1] + nums[i-1];
}
}
int sumRange(int i, int j) {
return dp[j+1] - dp[i];
}
private:
vector dp;
int countSubstrings(string s) {
int res = 0;
for(int i = 0; i < s.size();i++) {
helper(s,i,i,res);
helper(s,i,i+1,res);
}
return res;
}
void helper(string s,int i,int j,int &res) {
while (i >= 0 && j < s.size()) {
if (s[i] != s[j])
break;
i--,j++;
res++;
}
}
思路2:dp[i][j]定义成子字符串[i,j]是否为回文串,i从n-1开始向前遍历,j也从n-1向前遍历直到j == i,如果i ==j,那么[i,j]是回文串,如果i,j相邻或者中间隔一个数,那么比较s[i] == s[j]?如果相等,则是回文串,如果i和j中间隔大于一个数,那么判断dp[i+1][j-1]是否为真,若为真,则是回文串。
int countSubstrings(string s) {
int n = s.size();
int res = 0;
vector> dp(n,vector(n,false));
for (int i = n-1; i >= 0; i--) {
for (int j = n-1; j >= i; j--) {
if (s[i] == s[j] && (j - i <= 2 || dp[i+1][j-1]))
dp[i][j] = true;
if (dp[i][j]) res++;
}
}
return res;
}
int numberOfArithmeticSlices(vector& A) {
int n = A.size();
int res = 0;
vector 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;
}
思路2:可以不保存所有dp值,用一个变量代替就可。
int numberOfArithmeticSlices(vector& A) {
int n = A.size();
int res = 0;
int old = 0,cur = 0;
for (int i = 2; i < n; i++) {
if (A[i] - A[i-1] == A[i-1] - A[i-2]) {
cur = old + 1;
old = cur;
}
else {
old = 0;
cur = 0;
}
res += cur;
}
return res;
}
int minimumDeleteSum(string s1, string s2) {
int m = s1.size();
int n = s2.size();
vector> dp(m+1,vector(n+1,0));
for (int i = 1; i <= m; i++)
dp[i][0] = dp[i-1][0] + s1[i-1];
for (int j = 1; j <= n; j++)
dp[0][j] = dp[0][j-1] + s2[j-1];
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
dp[i][j] = s1[i-1] == s2[j-1] ? dp[i-1][j-1] :
min(dp[i-1][j] + s1[i-1],dp[i][j-1] + s2[j-1]);
}
}
return dp[m][n];
}
static bool vecSort( vector &a, vector &b) {
return a[1] < b[1];
}
int findLongestChain(vector>& pairs) {
int res = 0,end = INT_MIN;
sort(pairs.begin(),pairs.end(),vecSort);
for (auto pair : pairs) {
if (pair[0] > end) {
res++;
end = pair[1];
}
}
return res;
}
但是这样复杂度就是O(n^2),不是之前要求的O(n).O(n)的话需要找数学规律。
int integerBreak(int n) {
vector dp(n+1,1);
int t;
for (int i = 2; i <= n; i ++) {
for (int j = 1; j < i; j++) {
t = max(j * (i-j),dp[j] * (i - j));
dp[i] = max(t,dp[i]);
}
}
return dp[n];
}
int countNumbersWithUniqueDigits(int n) {
vector dp(n+1,1);
dp[1] = 10;
for (int i = 2; i < n + 1; i++) {
dp[i] = dp[i-1] + (dp[i-1] - dp[i-2])* (9 - i + 2);
}
return dp[n];
}
int minSteps(int n) {
vector dp(n+1,0);
for (int i = 2; i <= n; i++) {
dp[i] = i;
for (int j = 2; j < i; j++) {
if (i % j == 0) {
dp[i] = min(dp[i],dp[j] + i / j);
}
}
}
return dp[n];
}
bool PredictTheWinner(vector& nums) {
int n = nums.size();
vector> dp(n,vector(n,0));
for (int i = 0; i < n; i++) {
dp[i][i] = nums[i];
}
for (int len = 1; len < n; len++) {
for (int i = 0,j = len; j < n; i++,j++) {
dp[i][j] = max(nums[i] - dp[i+1][j],nums[j] - dp[i][j-1]);
}
}
return dp[0][n-1]>=0;
}
bool isSubsequence(string s, string t) {
int m = s.size();
int n = t.size();
int i = 0,j = 0;
while (i < m && j < n) {
if (s[i] == t[j]) {
i++;
j++;
}
else {
j++;
}
}
if (i == m) {
return true;
}
return false;
}
int uniquePaths(int m, int n) {
vector> dp(m,vector(n,1));
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
int deleteAndEarn(vector& nums) {
int n = nums.size();
vector dp(10001,0);
vector cnt(10001,0);
for(int i = 0; i < n; i++)
cnt[nums[i]]++;
dp[1] = cnt[1];
for (int i = 2; i < 10001; i++) {
dp[i] = max(dp[i-2] + cnt[i] * i,dp[i-1]);
}
return dp[10000];
}
int findTargetSumWays(vector& nums, int S) {
int res = 0;
helper(nums,S,0,res);
return res;
}
void helper(vector& nums,int 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);
}
int longestPalindromeSubseq(string s) {
int n = s.size();
vector> dp(n,vector(n,0));
for (int i = n - 1; i >= 0; i--) {
dp[i][i] = 1;
for (int j = i + 1; j < n; j++) {
if (s[i] == s[j])
dp[i][j] = dp[i+1][j-1] + 2;
else {
dp[i][j] = max(dp[i+1][j],dp[i][j-1]);
}
}
}
return dp[0][n-1];
}
int numTrees(int n) {
vector dp(n+1,0);
dp[0] = 1;
for (int i = 1; i <= n; i++) {
for (int j = 0; j < i; j++) {
dp[i] += dp[j] * dp[i - j - 1];
}
}
return dp[n];
}
64.Minimum Path Sum
思路:dp[i][j]表示i行j列最小路径和,因为只能向右和向下移动,所以dp[i][j] = min (dp[i-1][j],dp[i][j-1]) + grid[i][j];也就是说,dp[i][j]只能来自于它上面的块和左边的块,所以比较这两个大小,取其小的那一块就可以。代码中需要先初始化第一行和第一列dp值。
int minPathSum(vector>& grid) {
int n = grid.size();
int m = grid[0].size();
vector> dp = grid;
for (int i = 1; i < n; i++){
dp[i][0] = dp[i-1][0] + grid[i][0];
}
for (int i = 1; i < m; i++) {
dp[0][i] = dp[0][i-1] + grid[0][i];
}
for (int i = 1; i < n; i ++) {
for (int j = 1; j < m; j++) {
dp[i][j] = min (dp[i-1][j],dp[i][j-1]) + grid[i][j];
}
}
return dp[n-1][m-1];
}
377.Combination Sum IV
思路:第一想法是DFS,但是超时,所以还是用DP。dp[i] 表示和为i时,组合数,那么dp[i] = dp[i-nums[0] ] + dp[i - nums[1]] + …dp[i - nums[size-1]].用代码表示就是dp[i] += dp[i - num];
int combinationSum4(vector& nums, int target) {
int n = nums.size();
vector dp(target+1,0);
dp[0] = 1;
sort(nums.begin(),nums.end());
for(int i = 1; i <= target; i++) {
for (auto num : nums) {
if (num <= i)
dp[i] += dp[i - num];
}
}
return dp[target];
}
Maximum Length of Repeated Subarray
思路:dp[i][j]表示数组A中前i个字符和数组B前j个字符最长公共子数组的个数,如果A[i] == B[j],那么dp[i][j]等于dp[i-1][j-1] + 1,最后找到dp中最大值即可。其中有个小技巧,因为是从0开始计算,但是i-1和j-1不能是负数,所以i,j从1计数,但是比较还是i-1,j-1,相当于还是0,只是保存结果从[1][1]开始的。
int findLength(vector& A, vector& B) {
int m = A.size();
int n = B.size();
int res = 0;
vector> dp(m+1,vector(n+1,0));
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (A[i-1] == B[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
res = max(res,dp[i][j]);
}
}
}
return res;
}
72`edit distance
思路:
int minDistance(string word1, string word2) {
int m = word1.size();
int n = word2.size();
// vector> dp(m+1,vector(n+1,0));
int dp[m+1][n+1];
for (int i = 0; i < m + 1; i++)
dp[i][0] = i;
for (int i = 0; i < n + 1; i++)
dp[0][i] = i;
for (int i = 1; i < m + 1; i++) {
for (int j = 1; j < n + 1; 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],min(dp[i][j-1],dp[i-1][j-1])) + 1;//这里一定要注意,min函数只接受两个参数,必须写两个min
}
}
}
return dp[m][n];
}