leetcode 5172 形成三的最大倍数 (DP 贪心 DP路径打印)

23 篇文章 0 订阅

题目描述:

有一串数An,选出其中的子串,子串的和必须是3的倍数,且子串经过排列成为一个数字后,必须是所有可能的子串中最大的。

比如[ 1,2,3,4,5]我们直接选出54321级符合要求,3不是最大的。

稍稍吐槽一下,这道题是cf的原题。以前在cf上做用的贪心,刷刷刷就出来了,但是在这里惯性思维用了DP做。其实DP也没问题,关键这里的难点是需要打印最大的串。

解题思路:

我们令dp[pos][no]表示对当前A_{pos}前面所有项求和模3为no时,最长的符合要求的串是什么。为什么我们要求最长的符合要求的串呢?因为我们必须返回最大的数字,所以越长越大。

转移:

dp[pos][no]=max(dp[pos+1][(no+cur)\% 3]+1,dp[pos+1][no])

cur代表本次的数字.

代表的是本个数是否应该选。

最后我们可以得出最长串,最后的问题是怎么得到选哪个数字呢,这里我们需要贪心的思想,首先输入的数字从大到小排序,若

dp[pos+1][(no+cur)%3]==dp[pos][no]-1,证明本次是可以要的! 那么我们就尽可能地把它拿过来。

const int MAXN=1e4+10;
const int inf=1e9;
class Solution {
public:
    vector<int> arrmv;
    
    int dfs(int pos,int modn){
        if(pos==n && modn>0)return -inf;
        if(pos==n)return 0;
        if(dp[pos][modn]!=-1)return dp[pos][modn];
        
        int lv=dfs(pos+1,(modn+arrmv[pos])%3)+1;
        int rv=dfs(pos+1,modn);
        if(lv>rv)choice[pos][modn]=1;
        else choice[pos][modn]=0;
            
        return dp[pos][modn]=max(lv,rv);
    }
    int n;
    vector<vector<int>> dp;
        vector<vector<int>> choice;
    string largestMultipleOfThree(vector<int>& digits) {
        sort(digits.begin(),digits.end(),greater<int>());
        
        arrmv=digits;
        //for(auto it:arrmv)cout<<it<<" ";
        dp.assign(MAXN,vector<int>(3,-1));
        choice.assign(MAXN,vector<int>(3,-1));
        n=digits.size();
        dfs(0,0);
        //cout<<dp[0][0]<<endl;
        if(dp[0][0]<=0)return string("");
        vector<int> mv;
        int ls;
        for(int i=0;i<n;i++){
            if(!i)ls=0;
            if(i==n-1){
                if((arrmv.back()+ls)%3==0)mv.push_back(arrmv.back());
                break;
            }
            if(dp[i+1][(ls+arrmv[i])%3]==dp[i][ls]-1){
                //cout<<"pick "<<i<<endl;
                ls+=arrmv[i];
                ls%=3;
                mv.push_back(arrmv[i]);
            }
            
        }
        sort(mv.begin(),mv.end(),greater<int>());
        string ret("");
        int zf=1;
        for(auto it:mv){
            if(it>0)zf=0;
            ret+=it+'0';
        }
        if(zf)return string("0");
        return ret;
        
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值