
题目中需要注意的是,答案必须是子串的长度 ,那么就意味着是连续的,所有又可以用双指针的方法来进行求解。
cpp
class Solution {
public:
int lengthOfLongestSubstring(string s) {
if(s.size() == 0){
return 0;
}
unordered_set<char> s1;
int result = 0;
int left = 0;
for(int right = 0; right<s.size(); right++){
while(s1.find(s[right]) != s1.end()){ //s[right]在s1中找到
s1.erase(s[left]);
left++;
}
s1.insert(s[right]);
result = max(result, right-left+1);
}
return result;
}
};

超出时间限制:
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int plen = p.size();
vector<int> result;
sort(p.begin(), p.end());
for(int i = 0; (i+plen)<=s.size(); i++){
string sub = s.substr(i, plen);
sort(sub.begin(), sub.end());
if(sub == p){
result.push_back(i);
}
}
return result;
}
};
这个用sort在进行比较,比较耗费时间,不过先sort再判断是否相等是一般解决字母异位的方法,如字母异位词分组
优化:
cpp
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
vector<int> result;
if(s.size() < p.size()){
return result;
}
vector<int> plist(26);
vector<int> slist(26);
for(char ch : p){
plist[ch - 'a']++;
}
int left = 0;
for(int right = 0; right<s.size(); right++){
slist[s[right]-'a']++;
if(right-left+1 == p.size()){//滑动窗口体现在这里,每p的长度进行一次比较
if(slist==plist){
result.push_back(left);
}
slist[s[left] - 'a']--;//别忘了还需要减掉。这样保证slist里面始终与p的大小是相符合的
left++;
}
}
return result;
}
};
这个时间复杂度为O(n),双指针的方法用在这里很正常,比较新奇的一点是这个解法先定义了两个vector,然后利用字母出现的频次来判断是否异位,很巧妙。

这道题目同样可以用暴力解法进行求解,但是也会超时。
接下来来看前缀和+哈希表的解法:
cpp
class Solution {
public:
int subarraySum(vector<int>& nums, int k) {
unordered_map<int, int> map;
int result = 0;
int frontSum = 0;
map[0] = 1;
for(int num : nums){
frontSum += num;
if(map.find(frontSum - k) != map.end()){
result += map[frontSum - k];
}
map[frontSum]++;
}
return result;
}
};
前缀和很巧妙的可以只用遍历数组一次就可以得到,两个元素对应的前缀和相减就可以得到他们俩之间的元素的和。同时再创建一个unordered_map,其key为每个元素的前缀和,value为该前缀和出现的次数。需要注意的是map[0] = 1;因为可能出现仅一个元素就可满足。思路是:for循环计算每个元素所对应前缀和,然后找是否有两前缀和相减为k(也就是某一段数组的和为k),若有则算是找到了符合要求的子数组,加对应的次数。
根本是没有想到前缀和。

cpp
class Solution {
public:
int maxSubArray(vector<int>& nums) {
if(nums.size()==1){
return nums[0];
}
int frontSum = 0;
int minfrontSum = 0;
int maxSum = INT_MIN;
int result = 0;
for(int i = 0; i<nums.size(); i++){
frontSum += nums[i];
maxSum = max(maxSum, frontSum-minfrontSum);
minfrontSum = min(minfrontSum, frontSum);
}
return maxSum;
}
};
我刚开始的错误思路:也是利用前缀和,但我是找了最大的前缀和和最小的前缀和,然后它俩相减就是最大和的连续子数组,只能通过部分测试用例。分析后发现这样对于连续负数的数组是错误的,考虑不够全面。所以应该是利用前缀和并且记录此前面的最小的前缀和.
本集心得:
自己写的全只能通过部分用例,哈哈,还是考虑的不够全面,哈哈