1. 问题:
Given a string, find the length of the longest substring without repeating characters.
Examples:
Given "abcabcbb"
, the answer is "abc"
, which the length is 3.
Given "bbbbb"
, the answer is "b"
, with the length of 1.
Given "pwwkew"
, the answer is "wke"
, with the length of 3. Note that the answer must be a substring, "pwke"
is a subsequence and not a substring.
2方法:
方法1. 最常见的冒泡: Me
class Solution {
public:
int lengthOfLongestSubstring(string s)
{
string tmp_result;
int tmp_maxlen = 0;
int len = s.length();
int j = 0;
int i = 0;
int maxlen = 0;
int flag_break = 0;
for (i=0; i<len; i++)
{
for (j=i; j<len; j++)
{
// cout << "i:" << i << ",s[j]"<< s.at(j) << endl;
if (tmp_result.find(s.at(j)) == string::npos)
{
tmp_result.append(s,j,1);
}
else
{
tmp_maxlen = j - i;
break;
}
}
if (j == len)
{
tmp_maxlen = j - i ;
}
//cout << "maxlen:" << maxlen << " tmp_maxlen:" << tmp_maxlen << endl;
if (tmp_maxlen > maxlen){
maxlen = tmp_maxlen;
}
//cout << "tmp_result:" << tmp_result << endl;
tmp_result.clear();
}
return maxlen;
}
};
方法1.1 (借鉴方法2的思路):
#include<iostream>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
int main()
{
map<char,int> map;
string s;
cin >> s;
int i = 0, maxlen = 0, start = 0;
for(i = 0; i< s.length(); i++)// 遍历
{
if (map.find(s[i]) == map.end()) //子序列中没有重复的
{
cout << "not find i:" << i << ",start:"<< start <<",maxlen" << maxlen << endl;
map[s[i]] = i; // add
maxlen = max(maxlen,i-start+1);
cout << "update maxlen:" << maxlen << endl;
}else
{
cout << "has find i:" << i << ",start:"<< start <<",maxlen" << maxlen << endl;
map.clear();// TODO:时间复杂度 o(lgn)还是O(n)
map[s[i]] = i; // add. important.
start = i;
}
}
cout <<"maxlen:" << maxlen << endl;
return 0;
}
方法2: java
思路: if s[j] have a duplicate in the range [i,j) with index j′, we don't need to increase i little by little. We can skip all the elements in the range [i,j′] and let i to be j′+1 directly.
public class Solution {
public int lengthOfLongestSubstring(String s) {
int n = s.length(), ans = 0;
Map<Character, Integer> map = new HashMap<>(); // current index of character
// try to extend the range [i, j]
for (int j = 0, i = 0; j < n; j++) {
if (map.containsKey(s.charAt(j))) {
i = Math.max(map.get(s.charAt(j)), i);
}
ans = Math.max(ans, j - i + 1);
map.put(s.charAt(j), j + 1);
}
return ans;
}
}
方法3: C++
#include<iostream>
#include<vector>
#include<algorithm>
#include<map>
#include<string>
using namespace std;
int main()
{
map<char,int> map;
vector<int> dict(256,-1);// 初始化-1;字符串下标从0
string s;
cin >> s;
int i = 0, maxlen = 0, start = -1;//初始化-1;字符串下表从0
for(i = 0; i< s.length(); i++)// 遍历
{
if (dict[s[i]] > start)//s[i] 在 先前的子序列出现过
{
start = dict[s[i]];//新一轮计数位置
}
dict[s[i]] = i;
maxlen = max(maxlen,i-start);
}
cout <<"maxlen:" << maxlen << endl;
return 0;
}
总结: 要分析题目,找出特点或者规律. 写出良好的算法 【how?如何做到?简单的就是动笔画一遍处理流程】. 针对方法2的思路, 当在s[j] 在区间[i,j)中找到一个重复的值了,此时长度是j-i,那么在区间[i,j) 中不可能有更大的不重复的子串了。因此,下次直接从j开始扫描。