ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

LeetCode 2002. 两个回文子序列长度的最大乘积 DFS+状态压缩DP

2021-11-26 15:00:53  阅读:152  来源: 互联网

标签:int s2 s1 DFS 2002 length res 字符串 LeetCode


2002. 两个回文子序列长度的最大乘积

1.题目:

给你一个字符串 s ,请你找到 s 中两个 不相交回文子序列 ,使得它们长度的 乘积最大 。两个子序列在原字符串中如果没有任何相同下标的字符,则它们是 不相交 的。

请你返回两个回文子序列长度可以达到的 最大乘积 。

子序列 指的是从原字符串中删除若干个字符(可以一个也不删除)后,剩余字符不改变顺序而得到的结果。如果一个字符串从前往后读和从后往前读一模一样,那么这个字符串是一个 回文字符串 。

2.思路:

  • 暴力dfs

对于字符串中的一个字符,有三种情况

  1. 放入第一个字符串

  2. 放入第二个字符串

  3. 都不放入

    暴力递归即可

  • 状态压缩DP

在一个数组中,某个元素只有取和不取两种状态,例如【a,b,c】,则共有2^3种状态,【000,001,010,011,100,101,110,111】,如果该位置为1,则表示取该元素,例如110表示ab,当两个自己没有相同的元素时,即x&y=0,例如ac(101)&b(010)=0

此时我们便把一个bool数组压缩为一个整数,通过位运算来提高代码效率

对于字符串中的两个子序列,因为不能有相同的字符,所有子序列状态码相与等于0

此时我们直接暴力搜索每两个状态即可

//state_arr=[]存储所有的合法状态
for(int i=0;i<state_arr.size();i++){
	for(int j=i+1;j<state_arr.size();j++){
		if(state_arr[i]&state_arr[j]==0){
			////两个子集为j,j
		}
	}
}

优化:从大到小枚举每个状态中的子集与补集

for (int i = 1; i < m; i++) {
    int split = i >> 1;
    // 由于 j 与 i ^ j 是互补的关系,枚举到 i / 2即可,之后的会重复
    //j = (j - 1) & i,  j-1表示剔除j这个状态最后的一个1,但可能会在后面增加一个1,所有将它与i相与,即可保证j是i的子集
    for (int j = (i - 1) & i; j > split; j = (j - 1) & i) {
        //Code
        //两个子集为j,i^j
    }
}

3.Code

  • 暴力DFS
class Solution {
    int res=0;
    public int maxProduct(String s) {
        StringBuilder s1 = new StringBuilder(),s2 = new StringBuilder();
        this.dfs(s,s1,s2,0);
        return res;
    }
    public void dfs(String s,StringBuilder s1,StringBuilder s2,int index){
        if(check(s1) && check(s2)){
            res=Math.max(res,s1.length()*s2.length());
        }
        if(index==s.length()){
            return;
        }
        //加入第一个字符串
        s1.append(s.charAt(index));
        this.dfs(s,s1,s2,index+1);
        s1.deleteCharAt(s1.length()-1);
		//加入第二个字符串
        s2.append(s.charAt(index));
        this.dfs(s,s1,s2,index+1);
        s2.deleteCharAt(s2.length()-1);
		//不加入
        this.dfs(s,s1,s2,index+1);
    }


    public boolean check(StringBuilder s){
        if(s.length()<=0){
            return true;
        }
        for(int i=0,j=s.length()-1;i<s.length();i++,j--){
            if(s.charAt(i)!=s.charAt(j)){
                return false;
            }
        }
        return true;
    }
}
  • 状态压缩DP
class Solution {
    int res=0;
    public int maxProduct(String s) {
        int n=s.length();
        int m=1<<n;
        char[] str=s.toCharArray();
        int[] count =new int[m];
        //获取每个合法状态的1的位数
        for (int i = 0; i < m; i++) {
            if(check(s,i)){
                count[i]=Integer.bitCount(i);
            }
        }
       	//枚举s的每个子序列的每个子集和该子集的补集
        for (int i = 0; i <m ; i++) {
            for(int j=i;j>0;j=(j-1)&i){
                res=Math.max(res,count[j]*count[i^j]);
            }
        }
        return res;
    }

    public boolean check(String s,int state) {
        int l=0,r=s.length()-1;
        while(l<r){
            while(l<r && ((state>>l&1)==0)){
                l++;
            }
            while(l<r && ((state>>r&1)==0)){
                r--;
            }
            if(s.charAt(l)!=s.charAt(r)){
                return false;
            }
            l++;
            r--;
        }
        return true;
    }
}

标签:int,s2,s1,DFS,2002,length,res,字符串,LeetCode
来源: https://www.cnblogs.com/iven98/p/15607876.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有