LeetCode --- 动态规划(二)

目录

 

132. 分割回文串 II

139. 单词拆分

140. 单词拆分 II

152. 乘积最大子序列

198. 打家劫舍

213. 打家劫舍 II

BZOJ 2151


132. 分割回文串 II

给定一个字符串 s,将 s 分割成一些子串,使每个子串都是回文串。

返回符合要求的最少分割次数。

示例:

输入: "aab"
输出: 1
解释: 进行一次分割就可将 s 分割成 ["aa","b"] 这样两个回文子串。

分析:  定义状态dp[i]表示分割字符串str[0,i]最少需要分割多少次。

状态转移:j位于0~i之间,如果str[j,i]是回文串,dp[i]就是dp[j-1] + 1, 因为对于s[j,i]已经是回文串了,所以做一次单独的分割,剩下的就是dp[j-1]。

可以用个标记数组mp[i][j]表示从i到j的字符串是回文串。

class Solution {
public:
    int minCut(string s) {
        
        int n = s.size();
        
        if(n<2)return 0;
        vector<int>dp(n,n);
        vector<vector<bool> > mp( n, vector<bool>(n,false) );
        dp[0] = 0;
        mp[0][0] = true;
        
        for(int i = 1;i < n;++i){
            
            for(int j = 0;j<=i;++j){
                if(s[i] == s[j] && ( i-j<2 || mp[j+1][i-1] ) )    {
                    dp[i] = min(dp[i],!j?0:dp[j-1]+1);
                    mp[j][i] = true;
                }
            }
        }
        return dp[n-1];
        
    }
};

139. 单词拆分

dp[i]:表示字符串s[0,i]可以被拆。然后他的状态对前面的暴力哈希判断就可以了。

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

140. 单词拆分 II

相比于上一题,打一下标记,找一下路径。

class Solution {
public:
    vector<string> path,res;
    
    vector<string> wordBreak(string s, vector<string>& wordDict) {
        int n = s.size();
        unordered_set<string> hs(wordDict.begin(),wordDict.end());
        vector<bool> dp(n+1,false);
        vector< vector<bool> > mp(n+1, vector<bool> (n+1,false));
        dp[0] = true;
        
        for(int i = 1;i<=n;++i)
            for(int j = 0;j<i;++j){
                if(dp[j] && hs.find( s.substr(j,i-j) ) != hs.end() ){
                    dp[i] = true;
                    mp[j][i] = true;
                }
            }
        
        getpath(s,mp,n,n);
        return res;
        
        
    }
    
    void getpath(string &s,vector< vector<bool> > &mp,int len,int cur){
        if(cur == 0){
            string tmp;
            for(auto it = path.rbegin();it!=path.rend();++it){
                tmp += *it;
                tmp += " ";
            }
            tmp.erase(tmp.end()-1);
            res.push_back(tmp);
            return;
        }
        
        for(int i = 0;i<len;++i){
            if(mp[i][cur]){
                path.push_back( s.substr(i,cur-i) );
                getpath(s,mp,len,i);
                path.pop_back();
            }
        }
    }
};

152. 乘积最大子序列

给定一个整数数组 nums ,找出一个序列中乘积最大的连续子序列(该序列至少包含一个数)。

分析:

当前数>0时,直接最大值就是*当期前数,否则用最小值*当前数。

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int ans = INT_MIN;
        int n = nums.size();
        vector<int> _max(n+1,INT_MIN),_min(n+1,INT_MAX);
        _max[0] = _min[0] = ans = nums[0];
        if(n <= 1)return nums[0];
        for(int i = 1;i<n;++i){
            if(nums[i] > 0){
                _max[i] = _min[i] = nums[i];
                _max[i] = max(_max[i],_max[i-1]*nums[i]);
                _min[i] = min(_min[i],_min[i-1]*nums[i]);
            }
            else{
                _max[i] = _min[i] = nums[i];
                _max[i] = max(_max[i],_min[i-1] * nums[i]);
                _min[i] = min(_min[i],_max[i-1] * nums[i]);
            }
            ans = max(ans,_max[i]);
        }
        return ans;
    }
};
 

198. 打家劫舍

简单的动态规划:

class Solution {
public:
    int rob(vector<int>& nums) {
        int n = nums.size();
        vector<int> dp(n,0);
        
        if(n==0)return 0;
        if(n==1)return nums[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];
        
        
    }
};

213. 打家劫舍 II

讨论下选0不选0号即可:

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

这两道题后面还有一道这样经典的题:如果限制可偷的数量,怎么写?

BZOJ 2151

Description

A城市有一个巨大的圆形广场,为了绿化环境和净化空气,市政府决定沿圆形广场外圈种一圈树。园林部门得到指令后,初步规划出n个种树的位置,顺时针编号1到n。并且每个位置都有一个美观度Ai,如果在这里种树就可以得到这Ai的美观度。但由于A城市土壤肥力欠佳,两棵树决不能种在相邻的位置(i号位置和i+1号位置叫相邻位置。值得注意的是1号和n号也算相邻位置!)。最终市政府给园林部门提供了m棵树苗并要求全部种上,请你帮忙设计种树方案使得美观度总和最大。如果无法将m棵树苗全部种上,给出无解信息。

Input

输入的第一行包含两个正整数n、m。第二行n个整数Ai。

Output

输出一个整数,表示最佳植树方案可以得到的美观度。如果无解输出“Error!”,不包含引号。

Sample Input

【样例输入1】
7 3
1 2 3 4 5 6 7
【样例输入2】
7 4
1 2 3 4 5 6 7
 

Sample Output

【样例输出1】
15

【样例输出2】
Error!

分析:我们对于这种不相邻问题有一种这样的处理办法:

用优先队列 + 链表的形式,选择队首元素Xi,然后把它相邻两个元素Xi-1 Xi+1取出, 然后两者相加,再减掉Xi后的值,再添加进去。如果下次取这个值的话,显然就是没取Xi,而是取了它相邻的元素。

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
//head

const int maxn = 1e6+11;
int nxt[maxn],pre[maxn],a[maxn];
bool vis[maxn];
int main() 
{
	priority_queue<pair<int,int> >q;
	int n,m;cin>>n>>m;
	
	for(int i = 1;i<=n;++i)scanf("%d",a+i),q.push(make_pair(a[i],i));
	for(int i = 1;i<n;++i)nxt[i] = i+1;nxt[n] = 1;
	for(int i = 2;i<=n;++i)pre[i] = i-1;pre[1] = n;
	if(m > n/2)return puts("Error!")&&1;
	ll ans = 0;
	while(m--){
		pair<int,int> tmp = q.top();q.pop();
		int x = tmp.second;
		while(vis[x]){tmp = q.top();x = tmp.second;q.pop();}
		int v = tmp.first;
		ans+=v;
		a[x] = a[pre[x]] + a[nxt[x]] - a[x];
		vis[pre[x]] = vis[nxt[x]] = true;
		pre[x] = pre[pre[x]];
		nxt[x] = nxt[nxt[x]];
		pre[ nxt[x] ] = x;
		nxt[ pre[x] ] = x;
		q.push(make_pair(a[x],x));
	}	
	cout << ans <<endl;

    return 0;
}

类似地一道题:BZOJ-1150

题意:给一条直线的坐标,每两个点可以用一根线连接,每个点只能连一根线,只能选择K个线,求线的总长度最短。

分析:连接相邻的,处理出来每两个相邻的距离,然后选择不相交最小,和上题类似:

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
const int mod = 1e9+7;
//head
 
const int maxn = 1e6+11;
int nxt[maxn],pre[maxn],a[maxn];
bool vis[maxn];
int main() 
{
    int n,k;cin>>n>>k;
    int last = 0;
    for(int i = 1;i<=n;++i){
        int x;cin>>x;
        a[i] = x - last;last = x;
        pre[i] = i-1,nxt[i] = i+1;
    }
    pre[2] = 0;nxt[n]=0;
    priority_queue< pair<int,int>,vector<pair <int,int> >, greater<pair<int,int> > > q;
    for(int i = 2;i<=n;++i) q.push(make_pair(a[i],i));
    int ans = 0;
    a[0] = inf;
    while(k--){
        pair<int,int> tmp = q.top();q.pop();
        int x = tmp.second;
        while(vis[x]){tmp = q.top();x = tmp.second;q.pop();}
        int v = tmp.first;
        //cout << v << endl;
        ans += v;
 
        a[x] = a[pre[x]] +a[nxt[x]] - a[x];
        vis[pre[x]] = vis[nxt[x]] = true;
        pre[x] = pre[pre[x]];
        nxt[x] = nxt[nxt[x]];
        pre[nxt[x]] = x;
        nxt[pre[x]] = x;
        q.push(make_pair(a[x],x));
    }   
    cout << ans <<endl;
    return 0;
}
发布了257 篇原创文章 · 获赞 36 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/sgh666666/article/details/91628035