LeetCode随笔之Dynamic programming

Dynamic Programming

  1. 牛牛在农场饲养了n只奶牛,依次编号为0到n-1, 牛牛的好朋友羊羊帮牛牛照看着农场.有一天羊羊看到农场中逃走了k只奶牛,但是他只会告诉牛牛逃走的k只奶牛的编号之和能被n整除。你现在需要帮牛牛计算有多少种不同的逃走的奶牛群。因为结果可能很大,输出结果对1,000,000,007取模。
    例如n = 7 k = 4:
    7只奶牛依次编号为0到6, 逃走了4只
    编号和为7的有:{0, 1, 2, 4}
    编号和为14的有:{0, 3, 5, 6}, {1, 2, 5, 6}, {1, 3, 4, 6},{2, 3, 4, 5}
    4只牛的编号和不会大于18,所以输出5.
    **思路:这道题在一个序列中,任意个数(本题为4个)的是和为sum的可能有多少个。
    代码:**
#include <iostream>  
using namespace std;
const int modMin = 1e9 + 7;
int main()
{
    int dp[55][1005] = { 0 };//加上这句比较好
    dp[0][0] = 1;
    int n, k;
    while (cin >> n >> k)
    {
        for (int i = 0; i<n; i++)
        {
            for (int j = k; j >= 1; j--)
            {
                for (int s = 0; s<n; s++)
                {
                    dp[j][s] = (dp[j][s] + dp[j - 1][(n + s - i) % n]) % modMin;
                }
            }
        }
        cout << dp[k][0] << endl;
    }
    return 0;
}
  1. 有一道题和上一道很像,是和为sum的所有数组有多少种。找到了,如下:
    Target Sum
    You are given a list of non-negative integers, a1, a2, …, an, and a target, S. Now you have 2 symbols + and -. For each integer, you should choose one from + and - as its new symbol.

Find out how many ways to assign symbols to make sum of integers equal to target S.

Example 1:
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.
**思路:先转化成和为sum,有多少中可能的序列的问题,然后规划。
代码:**

class Solution {
public:
    int findTargetSumWays(vector<int>& nums, int s) {
        int sum = accumulate(nums.begin(), nums.end(), 0);
        return sum < s || (s + sum) & 1 ? 0 : subsetSum(nums, (s + sum) >> 1); 
    }   

    int subsetSum(vector<int>& nums, int s) {
        int dp[s + 1] = { 0 };
        dp[0] = 1;//重要
        for (int n : nums)
            for (int i = s; i >= n; i--)
                dp[i] += dp[i - n];
        return dp[s];
    }
};
  1. Longest Palindromic Subsequence
    Given a string s, find the longest palindromic subsequence’s length in s. You may assume that the maximum length of s is 1000.

Example 1:
Input:

“bbbab”
Output:
4
One possible longest palindromic subsequence is “bbbb”.
Example 2:
Input:

“cbbd”
Output:
2
这道题的意思:比如一个字符串”axbcdxa”,最长回文是”axbxa”,答案是5。
**思路:如代码
代码:**

class Solution {
public:
    int longestPalindromeSubseq(string s) {
       int n=s.length();
        vector<vector<int>> dp(n,vector<int>(n));
        for(int i=n-1;i>=0;i--)//这种遍历方式更好。
        {
            for(int j=i;j<n;j++)
            {
                if(i==j)
                    dp[i][j]=1;
                else if(i+1==j)
                {
                    if(s[i]==s[j])
                        dp[i][j]=2;
                    else
                        dp[i][j]=1;
                }
                else
                {
                    if(s[i]==s[j])
                        dp[i][j]=max(max(dp[i+1][j],dp[i][j-1]),dp[i+1][j-1]+2);
                    else
                        dp[i][j]=max(max(dp[i+1][j],dp[i][j-1]),dp[i+1][j-1]);
                }
            }
        }
        return dp[0].back();
    }
};

4.Predict the Winner
Given an array of scores that are non-negative integers. Player 1 picks one of the numbers from either end of the array followed by the player 2 and then player 1 and so on. Each time a player picks a number, that number will not be available for the next player. This continues until all the scores have been chosen. The player with the maximum score wins.

Given an array of scores, predict whether player 1 is the winner. You can assume each player plays to maximize his score.

Example 1:
Input: [1, 5, 2]
Output: False
Explanation: Initially, player 1 can choose between 1 and 2.
If he chooses 2 (or 1), then player 2 can choose from 1 (or 2) and 5. If player 2 chooses 5, then player 1 will be left with 1 (or 2).
So, final score of player 1 is 1 + 2 = 3, and player 2 is 5.
Hence, player 1 will never be the winner and you need to return False.
Example 2:
Input: [1, 5, 233, 7]
Output: True
Explanation: Player 1 first chooses 1. Then player 2 have to choose between 5 and 7. No matter which number player 2 choose, player 1 can choose 233.
Finally, player 1 has more score (234) than player 2 (12), so you need to return True representing player1 can win.
**思路:dp[i][j]代表在i-j个数中,第一个人能取到的最大和是多少,则
若第一人取左边的数,能得到的最大值为left=sum(i-j)-dp[i+1][j];
若第一人取右边的数,能得到的最大值为right=sum(i-j)-dp[i][j-1];
所以dp[i][j]=max(dp[i+1][j],dp[i][j-1])。
最后判定一下第一个人取到的最大数,能够大于第二人即可。
代码:**

class Solution {
public:
    bool PredictTheWinner(vector<int>& nums) {
        int n=nums.size();
        if(n==1)
            return true;
        vector<vector<int>> dp(nums.size(),vector<int> (nums.size()));
        vector<int> ssum(n+1);
        ssum[0]=0;
        for(int i=0;i<n;i++)
        {
                ssum[i+1]+=ssum[i]+nums[i];

        }
        for(int i=n-1;i>=0;i--)
        {
            for(int j=i;j<n;j++)
            {
                if(i==j)
                    dp[i][j]=nums[i];
                else if(j-i==1)
                {
                    dp[i][j]=max(nums[i],nums[j]);
                }
                else
                {
                    int left=nums[i]+ssum[j+1]-ssum[i+1]-dp[i+1][j];
                    int right=nums[j]+ssum[j]-ssum[i]-dp[i][j-1];
                    dp[i][j]=max(left,right);
                }
            }
        }
        return dp[0][n-1]>=(ssum[n]-dp[0][n-1]);
    }
};
  1. Partition Equal Subset Sum
    Given a non-empty array containing only positive integers, find if the array can be partitioned into two subsets such that the sum of elements in both subsets is equal.

Note:
Each of the array element will not exceed 100.
The array size will not exceed 200.
Example 1:

Input: [1, 5, 11, 5]

Output: true

Explanation: The array can be partitioned as [1, 5, 5] and [11].
Example 2:

Input: [1, 2, 3, 5]

Output: false

Explanation: The array cannot be partitioned into equal sum subsets.
**思路:这题思路前所未闻!首先要#include,创建一个比特串。然后利用bits |=bits<

class Solution {
public:
    bool canPartition(vector<int>& nums) {
        bitset<200*100> bits(1);
        int ans=0;
        for(auto i : nums)
        {
            ans+=i;
            bits |= bits<<i;
        }
        return !(ans%2) && bits[ans>>1];
    }
};
  1. 简述:一个序列t,是否是另一个序列s的子序列。只要能按照顺序在s中找到t即可。
    **思路:it+=(*it==c)
    代码:**
class Solution {
public:
    bool isSubsequence(string s, string t) {
        string::iterator it=s.begin();
        for(char c:t)
        {
            it+= (*it==c);
        }
        return it==s.end();
    }
};
  1. Russian Doll Envelopes
    You have a number of envelopes with widths and heights given as a pair of integers (w, h). One envelope can fit into another if and only if both the width and height of one envelope is greater than the width and height of the other envelope.

What is the maximum number of envelopes can you Russian doll? (put one inside other)

Example:
Given envelopes = [[5,4],[6,4],[6,7],[2,3]], the maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).
**思路:先排序,再O(n^2)的去遍历,规划。
代码:**

    bool cmp(pair<int,int> i,pair<int, int> j)
    {
        if(i.first==j.first)
            return i.second<j.second;
        return i.first<j.first;
    }
class Solution {
public:
    int maxEnvelopes(vector<pair<int, int>>& envelopes) {
        sort(envelopes.begin(),envelopes.end(),cmp);
        int n=envelopes.size();
        int mx=n==0?0:1;
        vector<int> dp(n,1);
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<i;j++)
            {
                if(envelopes[i].first>envelopes[j].first && envelopes[i].second>envelopes[j].second)
                {
                    dp[i]=max(dp[j]+1,dp[i]);
                }
                mx=dp[i]>mx?dp[i]:mx;
            }
        }
        return mx;
    }

};
  1. 简述:一个数组中,最大能取到的数的和是多少?其中不能取相邻的数。
    **思路:如代码
    代码:**
class Solution {
public:
    int rob(vector<int>& nums) {
        int n=nums.size();
        if(n==0)
            return 0;
        vector<int> dp(n);
        for(int i=0;i<n;i++)
        {
            if(i==0)
                dp[i]=nums[i];
            else if(i==1)
                dp[i]=max(nums[i-1],nums[i]);
            else
            {
                dp[i]=max(dp[i-1],dp[i-2]+nums[i]);         
            }
        }
        return dp[n-1];
    }
};
  1. 有 n 个学生站成一排,每个学生有一个能力值,牛牛想从这 n 个学生中按照顺序选取 k 名学生,要求相邻两个学生的位置编号的差不超过 d,使得这 k 个学生的能力值的乘积最大,你能返回最大的乘积吗?
    输入:
    3
    7 4 7
    2 50
    输出:
    49
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
#include <string>
#include <map>

using namespace std;

int main(){
    int n;cin>>n;
    vector<int> A;
    for(int i=0;i<n;i++){
        int tmp;cin>>tmp;
        A.push_back(tmp);
    }
    int K,d;cin>>K>>d;
    long long int maxV=-99999999;
    long long int fmax[11][51],fmin[11][51];//二阶
    for(int i=0;i<=K;i++){
        for(int j=0;j<=n;j++)
        {
            fmax[i][j]=0,fmin[i][j]=0;
        }
    }
    for(int i=0;i<=n;i++){
        fmax[1][i]=A[i];fmin[1][i]=A[i];
        for(int k=2;k<=min(K,i+1);k++){//几个数参与相乘?
            for(int j=i-1;j>=0 && i-j<=d;j--){
                fmax[k][i]=max(fmax[k][i],max(fmax[k-1][j]*A[i],fmin[k-1][j]*A[i]));
                fmin[k][i]=min(fmin[k][i],min(fmin[k-1][j]*A[i],fmax[k-1][j]*A[i]));
            }
        }
        maxV=max(maxV,fmax[K][i]);
    }
    cout<<maxV;

    return 0;
}
  1. 一个序列{1,2,3},相加和为4的有多少可能,允许重复使用元素,且允许1,2,1和2,1,1是不同的两种可能。
//代码需要调整for循环的内外顺序即可,体会一下。这样每一次内循环都可以把所有的元素考虑进去,就会使得不同排列顺序的算是两种可能。
class Solution {
public:
    int combinationSum4(vector<int>& nums, int target) {
        if(nums.size()==0)return 0;
        vector<int> dp(target+1);
        dp[0]=1;
        for(int i=1;i<=target;i++){
            for(int j=0;j<nums.size();j++){
                if(nums[j]<=i)dp[i]+=dp[i-nums[j]];
            }
        }
        return dp[target];
    }
};
  1. 还有一种序列为2,3,6,7,target是7。这种保证序列没有重复元素,满足和为target的所有种类都要保存下来,并且不同于上题,2,2,3和2,3,2属于一种。所以可以顺序的把每一个元素放入。
//采用回溯,逐一放入,不行弹出。dfs
class Solution {
public:
    vector<vector<int>> res;
    vector<vector<int>> combinationSum(vector<int>& candidates, int target) {

        vector<int> tmp;
        set(candidates,target,tmp,0);
        return res;
    }
    void set(vector<int> &A,int target,vector<int> &tmp,int begin){
        if(!target){
            res.push_back(tmp);
            return;
        }
        for(int i=begin;i<A.size();i++){
            tmp.push_back(A[i]);
            if(target>=A[i])set(A,target-A[i],tmp,i);
            tmp.pop_back();
        }
    }
};
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值