3.无重复字符最长子串
3. 无重复字符的最长子串 ----LeetCode
方法一:
锻炼一下自己的注释,可能有点啰嗦。嘿嘿嘿~~~
思路:每次添加一个字符到最长无重复串中,用 i,j标记该子串的首尾,然后遍历一遍去判断当前加入子串的元素有没有重复,如果重复,找到重复的位置,并更新子串首部。
class Solution {
public:
//返回重复元素的位置,x表示当前最长子串的首部,y表示当前要加入最长子串的元素
int Pos(string s,int x, int y){
int pos=-1; // -1表示没有重复元素
while(x<y){
//找到第一个重复元素的位置即可停止
if(s[x]==s[y]){
pos = x;
break;
}
x++;
}
return pos;
}
int lengthOfLongestSubstring(string s) {
//每增加一个字符,就判断有没有重复
int n = s.length();
int ans=0;
if(n==0)
return ans;
//i表示最长子串首部,j指当前及加入元素,flag标志是否更新首部
int i=0,j=0,flag=0;
while(i<=j&&j<n){
int pos = Pos(s,i,j);
//更新头部
if(pos!=-1)
i=pos+1;
//j-i+1当前最长串的长度
ans = max(ans,j-i+1);
j++;
}
return ans;
}
};
时间复杂度:最坏情况,每次加入子串的元素都不重复,每次都要遍历整个子串,为O(n^2)
方法二:思路和上面的方法相同,不过在判断是否有重复元素,以及重复元素的位置时,可以选择用哈希表来更好更快的解决
class Solution {
public:
int lengthOfLongestSubstring(string s) {
// 哈希集合,记录每个字符是否出现过
unordered_set<char> occ;
int n = s.size();
// 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
int right = -1, ans = 0;
// 枚举左指针的位置,初始值隐性地表示为 -1
for (int i = 0; i < n; ++i) {
if (i != 0) {
// 左指针向右移动一格,移除一个字符
occ.erase(s[i - 1]);
}
//下一个元素如果不在哈希集合中,则添加进入,如果在则移动i,删除最左边的字符
while (right + 1 < n && !occ.count(s[right + 1])) {
// 不断地移动右指针
occ.insert(s[right + 1]);
++right;
}
// 第 i 到 right 个字符是一个极长的无重复字符子串
ans = max(ans, right - i + 1);
}
return ans;
}
};
时间复杂度:由于s仅被遍历一次,所以为O(N)
567.字符串的排列
本题的关键在于如何判读当前窗口中的s2的子串是s1一个排序。因为s1s2里面全是小写字母,我们可以用一个长度为26的数组表示每个子母出现的次数,当s2子串的长度与s1长度相等,且对应子母个数一样,此时即为一个排序。
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n = s1.length(),m = s2.length();
if(n>m)
return false;
unsigned nums[26];
for(unsigned i=0;i<26;i++){
nums[i] = 0;
}
//在s2中取前与s1相同长度的字符,统计各个字母的个数是否相等
for(int i=0;i<n;i++){
nums[s1[i]-'a']--;
nums[s2[i]-'a']++;
}
int diff=0;
for(unsigned i=0;i<26;i++){
if(nums[i]!=0)
diff++;
}
if(diff==0)
return true;
for(int i=n;i<m;i++){
//减去s2[i-n]=y,加入s2[i]=x
int x = s2[i]-'a',y = s2[i-n]-'a';
if(nums[x]==0)
diff++;
nums[x]++;
if(nums[x]==0)
diff--;
if(nums[y]==0)
diff++;
nums[y]--;
if(nums[y]==0)
diff--;
if(diff==0)
return true;
}
return false;
}
};
注:对于nums,s1里面含有的子母是做减法,表示当前还缺少那些子母,s2的子串是做加法。
同时,在移动窗口的时候,出窗口的子母个数要--,入窗口的子母个数要++。
时间复杂度:只需要遍历一次s2,所以为O(N)