题目要求
给你一个字符串数组 arr。字符串 s 由 arr 中具有唯一字符的子序列连接而成。
请返回 s 的最大可能长度。
子序列是一个数组,它可以在不改变其余元素顺序的情况下,通过删除某些元素或不删除任何元素从另一个数组派生出来。
简单来说我们需要组成尽可能长的字符串并且保证出现的字符是唯一的。
Example 1:
Input: arr = ["un","iq","ue"] Output: 4 Explanation: All the valid concatenations are: - "" - "un" - "iq" - "ue" - "uniq" ("un" + "iq") - "ique" ("iq" + "ue") Maximum length is 4.
Example 2:
Input: arr = ["cha","r","act","ers"] Output: 6 Explanation: Possible longest valid concatenations are "chaers" ("cha" + "ers") and "acters" ("act" + "ers").
Example 3:
Input: arr = ["abcdefghijklmnopqrstuvwxyz"] Output: 26 Explanation: The only string in arr has all 26 characters.
思路
找到由数组中的字符串组合而成的最长唯一字符串。关键点在于“唯一字符”,即任何字符在最终字符串中只能出现一次。
考虑使用‘set’追踪字符唯一性:‘set’自然的保证了其中元素的唯一性,因为不允许重复元素存在。
同一个字符串中的重复元素检查,采用‘insert’方法来判断返回值是否已经存在于‘set’中,如果插入的是已经存在的字符,会返回false。
采用回溯算法逐一探索所有可能的字符串组合。在每一步中:
- 如果当前考虑的字符串可以无重复地加入到当前组合中,我们就更新当前字符串组合和字符集合,然后递归地探索下一个选择。
- 完成探索后,通过“回溯”操作撤销上一步的选择,即从当前字符串组合中移除刚才添加的字符串,并从字符集合中删除相应的字符,以恢复到加入新字符串之前的状态。
代码
class Solution {
public:
bool isUnique(const string& str, const set<char>& currentSet) {
set<char> strSet;
for (char c : str) {
if (currentSet.find(c) != currentSet.end() || !strSet.insert(c).second) {
return false;
}
}
return true;
}
void backtrack(vector<string>& arr, int startIndex, set<char>& currentSet, string& currentString, int& maxLength) {
maxLength = max(maxLength, static_cast<int>(currentString.size()));
for (int i = startIndex; i < arr.size(); ++i) {
if (isUnique(arr[i], currentSet)) {
for (char c : arr[i]) {
currentSet.insert(c);
}
currentString += arr[i];
backtrack(arr, i+1, currentSet, currentString, maxLength);
for (char c : arr[i]) {
currentSet.erase(c);
}
currentString.erase(currentString.size() - arr[i].size());
}
}
}
int maxLength(vector<string>& arr) {
int maxLength = 0;
set<char> currentSet;
string currentString = "";
backtrack(arr, 0, currentSet, currentString, maxLength);
return maxLength;
}
};