leetcode3 无重复字符的最长子串
解法1:暴力法
解题步骤:
①找出字符串中的所有子串:两层循环实现
②判断子串中是否有重复字符:set实现
遍历子串,如果set中有该字符,则返回false,否则返回true
#include<iostream> #include<set> #include<string> using namespace std; class Solution{ public: int lengthOfLongestSubstring(string s){ int n = s.length(); int count=0; for(int i=0;i<n;++i){ for(int j=i+1;j<=n;++j){ if(allUnique(s,i,j)){ if(count<j-i) count = j-i; } } } return count; } bool allUnique(string s, int start, int end){ set<char> set; for(int i=start; i<end; ++i){ if(set.count(s[i]) != 0){ return false; } set.insert(s[i]); } return true; } }; int main(){ Solution solution; string s; cin>>s; int num; num = solution.lengthOfLongestSubstring(s); cout<<num<<endl; return 0; }
解法2:滑动窗口法
在本题中窗口表示不含重复字符的子串,用res表示最大不重复子串的长度。
为了计算滑动窗口的长度,我们用left表示窗口的左边界,窗口的右边界就是当前遍历到的字符。
如何判断字符重复出现?我们需要记录字符和它出现位置的映射。我们用一个256位大小的数组来代替哈希表表示字符最后出现的位置。该数组初始化全为0,表示所有字符都还没出现过。然后不断滑动窗口右边界,观察右边界对应的字符是否出现过,也即判断left是否需要更新。若数组中该字符对应的位置为0,则表示该字符从未出现过,left不变。若数组中该字符对应的位置不为0,说明该字符之前出现过,但是这个重复字符有可能在滑动窗口内部也有可能在滑动窗口左边。则接下来判断该字符是否在滑动窗口内部,若该字符的位置大于left,则表示该字符在滑动窗口内部,则移动left至重复字符处。若该字符的位置小于left,则表示该字符不在滑动窗口内部,无需更新left。
滑动窗口每次向右滑动一个字符,对应的数组中字符位置更新为i+1,然后比较res和滑动窗口的大小决定是否更新res。
class Solution{ public: int lengthOfLongestSubstring(string s){ int m[256] = {0}, res = 0, left = 0; for(int i=0;i<s.size();++i){ // if(m[s[i]] == 0 || m[s[i]] < left){ // res = max(res, i-left+1); // } // else{ // left = m[s[i]]; // } // m[s[i]] = i+1; ////精简写法 left = max(left, m[s[i]]); m[s[i]] = i+1; res = max(res, i-left+1); } return res; } };
解法2.2: 滑动窗口法
使用了HashMap建立字符和其最后出现位置之间的映射,其他操作同上
class Solution{ public: int lengthOfLongestSubstring(string s){ int res=0, left=0; unordered_map<char, int> m; for(int i=0;i<s.size();++i){ left = max(left, m[s[i]]); m[s[i]] = i+1; res = max(res, i-left+1); } return res; } };