题目描述:
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其
长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b"
,所以其长度为 1。
示例 3:
输入: "pwwkew" 输出: 3 解释: 因为无重复字符的最长子串是"wke"
,所以其长度为 3。 请注意,你的答案必须是 子串 的长度,"pwke"
是一个子序列,不是子串。
解题方法:
解法一:建立一个HashMap,建立每个字符和其最后出现位置之间的映射,然后我们需要定义两个变量res和left,其中res用来记录最长无重复子串的长度,left指向该无重复子串左边的起始位置的前一个,由于是前一个,所以初始化就是-1,然后我们遍历整个字符串,对于每一个遍历到的字符,如果该字符已经在HashMap中存在了,并且如果其映射值大于left的话,那么更新left为当前映射值。然后映射值更新为当前坐标i,这样保证了left始终为当前边界的前一个位置,然后计算窗口长度的时候,直接用i-left即可,用来更新结果res,代码如下:
int lengthOfLongestSubstring(string s) {
int res = 0, left = -1;//方法一
unordered_map<int, int> map;
for (int i = 0;i < s.size(); ++i) {
if (map.count(s[i]) && map[s[i]] > left) {
left = map[s[i]];
}
map[s[i]] = i;
res = max(res, i - left);
}
return res;
}
if判断的解释:一旦当前字符s[i]在HashMap已经存在映射,说明当前的字符已经出现过了,而若m[s[i]] > left 成立,说明之前出现过的字符在我们的窗口内,那么如果要加上当前这个重复的字符,就要移除之前的那个,所以我们让left赋值为m[s[i]],由于left是窗口左边界的前一个位置,所以相当于已经移除出滑动窗口了。
运行效率:36ms
解法二:
建立一个256位大小的整型数组来代替HashMap,这样做的原因是ASCII表共能表示256个字符,但是由于键盘只能表示128个字符,所以用128也行,然后我们全部初始化为-1,这样的好处是我们就不用像之前的HashMap一样要查找当前字符是否存在映射对了,对于每一个遍历到的字符,我们直接用其在数组中的值来更新left,因为默认是-1,而left初始化也是-1,所以并不会产生错误,这样就省了if判断的步骤,其余思路都一样:
int lengthOfLongestSubstring( string s) {
vector < int > m( 128 , - 1 );//方法二
int res = 0 , left = - 1 ;
for ( int i = 0 ; i < s.size(); ++ i) {
left = max(left, m[s[i]]);
m[s[i]] = i;
res = max(res, i - left);
}
return res;
}
运行效率:20ms
解法三:在提交记录中发现有一种方法效率8ms,下面简单介绍一下:
static int x = [](){ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();
class Solution {
public:
int lengthOfLongestSubstring(string s) {
vector <int>hax(128,-1);
int res=0;
int left=-1;
for(int i=0;i<s.size();++i)
{
left=max(left,hax[s[i]]);
hax[s[i]]=i;
res=max(i-left,res);
}
return res;
}
};
这里着重解释一下static int x = [](){ios::sync_with_stdio(false); cin.tie(nullptr); return 0; }();这段代码。
这种写法是Lambda捕获(Lambda表达式是C++11引入的特性,是一种描述函数对象的机制,它的主要应用是描述某些具有简单行为的函数。Lambda也可以称为匿名函数。)
std::ios::sync_with_stdio(false),Sets whether the standard C++ streams are synchronized to the standard C streams after each input/output operation.
设置在每次输入/输出操作后标准C ++流是否与标准C流同步。
其实主要原因就是C++中的cin和cout为了兼容C,不会与scanf和printf混乱,C++用一个流缓冲区来同步C的标准流,而std::ios::sync_with_stdio函数可以解除该同步,使之不经过缓冲区而节省时间。
由于std :: cin默认是与std :: cout绑定的,所以每次操作的时候(也就是调用”<<”或者”>>”)都要刷新(调用flush),这样增加了IO的负担,通过tie(nullptr)来解除std :: cin和std :: cout之间的绑定,来降低IO的负担使效率提升。
从而很大程度的提升了代码运行效率。