题目描述
当一个字符串 s
包含的每一种字母的大写和小写形式 同时 出现在 s
中,就称这个字符串 s
是 美好 字符串。比方说,"abABB"
是美好字符串,因为 'A'
和 'a'
同时出现了,且 'B'
和 'b'
也同时出现了。然而,"abA"
不是美好字符串因为 'b'
出现了,而 'B'
没有出现。
给定一个字符串 s
,请你返回 s
最长的 美好子字符串。如果有多个答案,请你返回 最早 出现的一个。如果不存在美好子字符串,请你返回一个空字符串。
样例
输入:s = "YazaAay"
输出:"aAa"
解释:"aAa" 是一个美好字符串,因为这个子串中仅含一种字母,其小写形式 'a' 和大写形式 'A' 也同时出现了。
"aAa" 是最长的美好子字符串。
输入:s = "Bb"
输出:"Bb"
解释:"Bb" 是美好字符串,因为 'B' 和 'b' 都出现了。整个字符串也是原字符串的子字符串。
输入:s = "c"
输出:""
解释:没有美好子字符串。
输入:s = "dDzeE"
输出:"dD"
解释:"dD" 和 "eE" 都是最长美好子字符串。
由于有多个美好子字符串,返回 "dD" ,因为它出现得最早。
限制
1 <= s.length <= 100
s
只包含大写和小写英文字母。
算法
(暴力枚举,哈希表) $O(n^2)$
- 使用哈希表来记录当前子串中每个大写字母和小写字母出现的次数。
- 按长度枚举所有子串,枚举的过程中,根据增/减的字符来调整记录的哈希表,进而判断合法性。
时间复杂度
- 共有 $O(n^2)$ 个子串,每个子串判断需要 $O(1)$ 的时间,故总时间复杂度为 $O(n^2)$。
空间复杂度
- 需要 $O(n)$ 的额外空间存储答案。
C++ 代码
class Solution {
private:
bool check(const vector<int> &upper, const vector<int> &lower) {
for (int i = 0; i < 26; i++)
if ((upper[i] && !lower[i]) || (!upper[i] && lower[i]))
return false;
return true;
}
public:
string longestNiceSubstring(string s) {
const int n = s.size();
for (int len = n; len >= 2; len--) {
vector<int> upper(26, 0), lower(26, 0);
for (int i = 0; i < len - 1; i++)
if (s[i] >= 'A' && s[i] <= 'Z') upper[s[i] - 'A']++;
else lower[s[i] - 'a']++;
for (int i = 0; i < n - len + 1; i++) {
int j = i + len - 1;
if (s[j] >= 'A' && s[j] <= 'Z') upper[s[j] - 'A']++;
else lower[s[j] - 'a']++;
if (check(upper, lower))
return s.substr(i, len);
if (s[i] >= 'A' && s[i] <= 'Z') upper[s[i] - 'A']--;
else lower[s[i] - 'a']--;
}
}
return "";
}
};
O(n)时间复杂度解法:
首先先求一个范围内的所有的大小写字母,然后双指针判断,如果发现当前字母在这个范围内不是大小写都有,则表示这个字母不能取,迭代前面和后面部分。
如果整个字符串都有,则说明这个范围的字符串符合要求,进行更新。
看起来有递归是O(nlogn)复杂度,但是因为每次递归的条件是某个字母的大小写不全在范围内,所以每次会少一个字母,因此时间复杂度O(26n)