题目描述
给定一个字符串 s
,请你拆分该字符串,并返回拆分后唯一子字符串的最大数目。
字符串 s
拆分后可以得到若干 非空子字符串 ,这些子字符串连接后应当能够还原为原字符串。但是拆分出来的每个子字符串都必须是 唯一的。
注意:子字符串 是字符串中的一个连续字符序列。
样例
输入:s = "ababccc"
输出:5
解释:一种最大拆分方法为 ['a', 'b', 'ab', 'c', 'cc']。
像 ['a', 'b', 'a', 'b', 'c', 'cc'] 这样拆分不满足题目要求,
因为其中的 'a' 和 'b' 都出现了不止一次。
输入:s = "aba"
输出:2
解释:一种最大拆分方法为 ['a', 'ba']。
输入:s = "aa"
输出:1
解释:无法进一步拆分字符串。
限制
1 <= s.length <= 16
s
仅包含小写英文字母。
算法
(递归回溯) $O(n2^n)$
- 递归回溯,最多有 $2^{n-1}$ 种拆分方式。
- 递归尝试当前位置是否需要拆分,如果拆分,则要保证当前子串没有在哈希表中出现过。
时间复杂度
- 最多有 $2^{n-1}$ 种拆分方式,每种方式都需要 $O(n)$ 的时间来判断字符串是否在哈希表中,故总时间复杂度为 $O(n2^n)$。
空间复杂度
- 需要 $O(n)$ 的额外空间存储哈希表和系统栈。
C++ 代码
class Solution {
private:
string cur;
int n, ans;
unordered_set<string> seen;
void solve(int i, int num, const string &s) {
cur += s[i];
if (i == n - 1) {
if (seen.find(cur) == seen.end())
ans = max(ans, num);
cur.pop_back();
return;
}
solve(i + 1, num, s);
if (seen.find(cur) == seen.end()) {
string tmp(cur);
seen.insert(cur);
cur.clear();
solve(i + 1, num + 1, s);
cur = tmp;
seen.erase(cur);
}
cur.pop_back();
}
public:
int maxUniqueSplit(string s) {
n = s.size();
ans = 0;
solve(0, 1, s);
return ans;
}
};