字符串仅包含大小写字母,则字符集是已知且有限的,那这种情况下我们可以考虑快速查找某个元素是否出现过的哈希表——只需要维护一个哈希表,将字符串T中的字符作为key值,初始化时当字符在T中出现一次则对应的value值减1:
for(int i = 0; i < T.length(); i++)
//初始化哈希表都为负数,找的时候再加为正
hash[T.charAt(i)] -= 1;
后续如果在字符串S中找到相应字符就可以将其加回来:
char c = S.charAt(fast);
//目标字符匹配+1
hash[c]++;
然后使用双指针维护滑动窗口,在窗口内,哈希表中value都大于0:
for (int i = 0; i < hash.length; i++) {
if (hash[i] < 0)
return false;
}
return true;
这个窗口内出现了T中所有的字符串,此时可以尝试缩小窗口,因为双指针同步向右遍历,因此缩小窗口只能是缩小左界。
class Solution {
public:
//检查是否有小于0的
bool check(unordered_map<char, int> &hash) {
for (auto iter = hash.begin(); iter != hash.end(); iter++) {
if (iter->second < 0)
return false;
}
return true;
}
string minWindow(string S, string T) {
int cnt = S.length() + 1;
//记录目标字符串T的字符个数
unordered_map<char, int> hash;
for(int i = 0; i < T.length(); i++)
//初始化哈希表都为负数,找的时候再加为正
hash[T[i]] -= 1;
int slow = 0, fast = 0;
//记录左右区间
int left = -1, right = -1;
for(; fast < S.length(); fast++){
char c = S[fast];
//目标字符匹配+1
if(hash.count(c))
hash[c]++;
//没有小于0的说明都覆盖了,缩小窗口
while(check(hash)){
//取最优解
if(cnt > fast - slow + 1){
cnt = fast - slow + 1;
left = slow;
right = fast;
}
char c = S[slow];
if(hash.count(c))
//缩小窗口的时候减1
hash[c]--;
//窗口缩小
slow++;
}
}
//找不到的情况
if (left == -1)
return "";
return string(S.begin() + left, S.begin() + (right + 1));
}
};
时间复杂度:O(C∗nS+nT)其中C为T字符串的字符集大小,本题中为52个字母,nS为字符串S的长度,nT为字符串T的长度
空间复杂度:O©,哈希表长度不会超过字符串T的字符集大小
开辟一个和str长度大小相同的一个字符串ans,把传入的str倒序赋值到ans字符串上
class Solution {
public:
string solve(string str) {
string ans = str;
int len = str.length();
for(int i = 0 ; i < len ;i++)
{
ans[i] = str[len-1-i];
}
return ans;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
原地交换,str[i]=str[len-i-1],注意:交换进行的次数是len/2次
class Solution {
public:
string solve(string str) {
int len = str.length();
for(int i = 0 ; i < len/2 ;i++)
{
swap(str[i],str[len-1-i]);
}
return str;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
class Solution {
public:
string solve(string str) {
reverse(str.begin(),str.end());
return str;
}
};
既然要找一段连续子数组的内不重复的长度,我们可以使用滑动窗口,保证窗口内都是不重复的,然后窗口右界不断向右滑,如果窗口内出现了重复数组,说明新加入的元素与之前的重复了,只需要窗口左界也向右收缩就可以保证窗口内都是不重复的。
而保证窗口内的元素不重复,我们可以使用根据key值快速访问的哈希表,key值为窗口内的元素,value为其出现次数,只要新加入窗口的元素出现次数不为1,就是重复。
while(mp.get(arr[right]) > 1)
//窗口左移,同时减去该数字的出现次数
mp.put(arr[left],mp.get(arr[left++])-1);
class Solution {
public:
int maxLength(vector<int>& arr) {
//哈希表记录窗口内非重复的数字
unordered_map<int, int> mp;
int res = 0;
//设置窗口左右边界
for(int left = 0, right = 0; right < arr.size(); right++){
//窗口右移进入哈希表统计出现次数
mp[arr[right]]++;
//出现次数大于1,则窗口内有重复
while(mp[arr[right]] > 1)
//窗口左移,同时减去该数字的出现次数
mp[arr[left++]]--;
//维护子数组长度最大值
res = max(res, right - left + 1);
}
return res;
}
};
时间复杂度:O(n),外循环窗口右界从数组首右移到数组尾,内循环窗口左界同样如此,因此复杂度为O(n+n)=O(n)
空间复杂度:O(n),最坏情况下整个数组都是不重复的,哈希表长度就为数组长度n