import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
/**
* 1239. 串联字符串的最大长度
*
* 首先分析题意:在给定的字符串数组中进行选择,让选择的结果尽可能多的去覆盖一个1 * 26的矩阵
* (每个字母只能出现一次,所以最大为 1 * 26)
*
* 常用解法:剪枝DFS(暴力DFS比较简单,但是容易超时,所以需要剪枝优化)
* 1 预处理字符串:题目中并没有说明字符串中每一个字符只能出现一次,所以我们假定在一个字符串中
* 字符可以出现多次,进行预处理
*
* 2 如何表示一个字符串中的全部字符?对于任何一个字符串,我们只关心一个字符是否出现,
* 而不关心该字符到底出现了几次。所以使用 int 类型,使用其中的低24位来表示一个字符串中
* 出现了那些字符,使用位运算来确定该字符串是否能被拼接
*
* 3 如何剪枝:在处理过程中维护一个 surplusValue,代表未处理的字符串中剩余的最大价值
*
* 4 保存每个状态下的对应的字符串长度,为了便于查询与比较,使用HashMap
*/
public class Solution {
private Map<Integer, Integer> resMap = new HashMap<>();
private int ans = Integer.MIN_VALUE;
public int maxLength(List<String> arr) {
HashSet<Integer> set = new HashSet<>();
arr.forEach(str ->{
int flag = 0;
for (char ch : str.toCharArray()) {
int position = (ch - 'a');
if (((flag >> position) & 1) != 0) {
flag = -1;
break;
}
flag |= (1 << position);
}
if (flag != -1) {
set.add(flag);
}
});
int allStr = set.size();
if (allStr == 0) {
return 0;
}
int[] hash = new int[allStr];
int idx = 0;
int total = 0;
for (Integer i : set) {
hash[idx++] = i;
total |= i;
}
dfs(0, 0, total, allStr, hash);
return ans;
}
private void dfs(int u, int cur, int total, int allStr, int[] hash) {
if (get(cur | total) <= ans) {
return;
}
if (u == allStr) {
ans = Math.max(ans, get(cur));
return;
}
if ((hash[u] & cur) == 0) {
dfs(u + 1, hash[u] | cur, total - (total & hash[u]), allStr, hash);
}
dfs(u + 1, cur, total, allStr, hash);
}
private int get(int cur) {
if (resMap.containsKey(cur)) {
return resMap.get(cur);
}
int ans = 0;
for (int i = cur; i > 0; i-= lowBit(i)) {
ans++;
}
resMap.put(cur, ans);
return ans;
}
private int lowBit(int x) {
return x & -x;
}
}
LeetCode -- 1239. 串联字符串的最大长度
最新推荐文章于 2022-09-30 13:09:38 发布