LeetCode 1239. 串联字符串的最大长度(状压dp)

1.题目

2.求解

这道题似乎没有我想象的那么难,我用状压dp去求解似乎有点大材小用,效率也不是特别好。我看三叶姐用dfs+剪枝就做出来了,思索,我的脑子里是不是看到啥题都像DP :(

        不管怎么说是写出来了,给大家讲讲我的想法,如果有状压dp基础的大伙们(我相信大家都很强)肯定知道用二进制数组表示当前状态,我用数组下标表示我取了哪些字符串,dp数组内仍为一个二进制数,26位的,也就是当前所取的字符串内包含的所有字符。

        因为都是字符串操作,因此也就无法使用正常的状态转移方程,换种方式写:

if(!(i & (1 << j))){
   int num = to2(arr[j]);    //to2 函数是用来将字符串转换成二进制
   if(num == -1) continue;
   if(!(dp[i] & num)){
   dp[i | (1 << j)] = dp[i] | num;
   ans = max(ans, __builtin_popcount(dp[i | (1 << j)]));
}

        思索没有状态转移方程还能叫动态规划吗?

        如果上面这段代码有点无头无尾,那么就上完整代码:

3.代码

int dp[(1 << 16)];
class Solution {
public:
    int to2(string str){
        int ans = 0;
        int num;
        for(int i = 0; i < str.size(); i++){
            num = 1 << (str[i] - 'a');
            if (ans & num) return -1;
            ans += num;
        }
        return ans;
    }
    int maxLength(vector<string>& arr) {
        memset(dp, -1, sizeof(dp));
        int i, j;
        int len = arr.size();
        dp[0] = 0;
        int ans = 0;
        for(i = 0; i < (1 << len); i++){
            if (dp[i] == -1) continue;
            for(j = 0; j < len; j++){
                if(!(i & (1 << j))){
                    int num = to2(arr[j]);
                    if(num == -1) continue;
                    if(!(dp[i] & num)){
                        dp[i | (1 << j)] = dp[i] | num;
                        ans = max(ans, __builtin_popcount(dp[i | (1 << j)]));
                    }
                }
            }
        }
        return ans;
    }
};

4.优化

        我对选择字符串处进行了一定的优化,字符串数组只会从当前选过得最高位再往后取,实际上就是多了一行对j选值的if语句,看效果是还不错,给大家看看改过后的代码:

int dp[(1 << 16)];
class Solution {
public:
    int to2(string str){
        int ans = 0;
        int num;
        for(int i = 0; i < str.size(); i++){
            num = 1 << (str[i] - 'a');
            if (ans & num) return -1;
            ans += num;
        }
        return ans;
    }
    int maxLength(vector<string>& arr) {
        memset(dp, -1, sizeof(dp));
        int i, j;
        int len = arr.size();
        dp[0] = 0;
        int ans = 0;
        for(i = 0; i < (1 << len); i++){
            if (dp[i] == -1) continue;
            if(i == 0) j = 0;
            else j = int(log(i) + 1);
            for(; j < len; j++){
                if(!(i & (1 << j))){
                    int num = to2(arr[j]);
                    if(num == -1) continue;
                    if(!(dp[i] & num)){
                        dp[i | (1 << j)] = dp[i] | num;
                        ans = max(ans, __builtin_popcount(dp[i | (1 << j)]));
                    }
                }
            }
        }
        return ans;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值