题目来源:https://leetcode-cn.com/problems/maximum-product-of-the-length-of-two-palindromic-subsequences/
大致题意:
从给定字符串中找出两个不相交的回文子序列,给出两个子序列长度乘积可能的最大值。
思路
一开始就想到了用状态压缩的方法来解决字符串相交的问题,可是想不出怎么分配和遍历两个子串,水平不够。看了题解才明白。
状态压缩 + 遍历
- 首先,使用一个和给定字符串长度一样的二进制数来表示子串,即状态压缩,从低位到高位,二进制数第 i 位为 1 就代表子串包含字符串第 i 位的字符。
- 然后,获取字符串的长度 n ,遍历所有 n 位二进制数,也就是所有压缩后的状态,也就代表所有可能的子串。若当前子串是回文串,就用集合存下当前状态和对应的子串长度
- 接着,遍历所有存下的回文子串,对于每个子串,再在还未遍历的子串中找到和它不相交的,然后获取两个子串长度的乘积,更新最大值
代码:
public int maxProduct(String s) {
int n = s.length();
int m = 1 << n; // 状态个数
List<int[]> stateList = new ArrayList<int[]>();
// 遍历所有状态
for (int i = 0; i < m; i++) {
// 若当前状态是回文串
if (check(s, i)) {
// 将状态和对应的字符串长度入集合
stateList.add(new int[]{i, Integer.bitCount(i)});
}
}
int ans = 1;
// 遍历所有的回文串
for (int i = 0; i < stateList.size(); i++) {
// 获取子串 1
int s1 = stateList.get(i)[0];
int s1Len = stateList.get(i)[1];
for (int j = i+1; j < stateList.size(); j++) {
// 获取子串 2
int s2 = stateList.get(j)[0];
int s2Len = stateList.get(j)[1];
// 两个子串不相交
if ((s1 & s2) == 0) {
// 更新
ans = Math.max(ans, s1Len*s2Len);
}
}
}
return ans;
}
// 检查字符串 s 的 子串(状态压缩后的state) 是否为回文串
public boolean check(String s, int state) {
int left = 0;
int right = s.length() - 1;
while (left < right) {
// 若子串中不含当前位置字符,继续向右查找
while (left < right && (state >> left & 1) == 0) {
left++;
}
// 若子串中不含当前位置字符,继续向左查找
while (left < right && (state >> right & 1) == 0) {
right--;
}
if (s.charAt(left) != s.charAt(right)) {
return false;
}
left++;
right--;
}
return true;
}