描述:给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
输入: s = "abcabcbb"
输出:3 解释: 因为无重复字符的最长子串是"abc",所以其
长度为 3。
输入: s = "bbbbb"输出: 1
解释: 因为无重复字符的最长子串是"b",所以其长度为1.
=================================================================
思路一:暴力求解,依次从左往右,遇到相同的就直接结束,然后从后面一个字符开始,
最后的出最长子串。
{(a)bcabcbb}(a)bcabcbb 开始的最长字符串为 {(abc)abcbb}(abc)abcbb;
{a(b)cabcbb}a(b)cabcbb 开始的最长字符串为 {a(bca)bcbb}a(bca)bcbb;
{ab(c)abcbb}ab(c)abcbb 开始的最长字符串为 {ab(cab)cbb}ab(cab)cbb;
{abc(a)bcbb}abc(a)bcbb 开始的最长字符串为 {abc(abc)bb}abc(abc)bb;
{abca(b)cbb}abca(b)cbb 开始的最长字符串为 {abca(bc)bb}abca(bc)bb;
{abcab(c)bb}abcab(c)bb 开始的最长字符串为 {abcab(cb)b}abcab(cb)b;
{abcabc(b)b}abcabc(b)b 开始的最长字符串为 {abcabc(b)b}abcabc(b)b;
{abcabcb(b)}abcabcb(b) 开始的最长字符串为 {abcabcb(b)}abcabcb(b)。
完整代码如下:
public int lengthOfLongestSubstring(String s){ int max = 0; HashMap<Character,Integer> map = new HashMap<>(); for(int i = 0;i<s.length();i++){ int cur = 0; //每次都要清零整个HashMap表
map.clear(); for(int j = i;j<s.length();j++){ if(map.containsKey(s.charAt(j))){ //遇到相同的则直接跳出循环
break; } map.put(s.charAt(j),j); cur++; } max = Math.max(max,cur); } return max; }

=================================================================
思路二:利用滑动窗口:类似于一个队列,比如例题中的 abcav,进入这个窗口为 abc
满足题目要求,当再进入 a队列变成了 abca,这时候不满足要求。所以,我们
要移动这个队列,此时的窗口值为bca即left移动到,b位置,移动到重复值a的后
一位。相当于将与当前相同的值的左边全部移出窗口.
时间复杂度:O(n)
===========================================================================
什么是滑动窗口:
滑动窗口算法是在一个特定大小的字符串或数组上进行操作,而不在整个
字符串和数组上操作,这就降低了问题的复杂度,从而也降低了循环的嵌套深度,
滑动窗口主要应用在数组和字符串的场景。
================================================================================
滑动窗口的基本步骤:
需要注意的是:窗口的移动是按照移动的顺序来进行的;窗口的大小不一定是固
定的,可以不断缩小或变大的。
对于滑动窗口算法的基本解题思路,以字符串S示例如下:
1.采用双指针来指定窗口的范围,初始化left= right=0,而索引闭区间[left,right]
便是一个窗口。
2.不断增大窗口的right指针,直到窗口的字符串满足要求。
3.此时停止right的增加,转而不断增加left指针,用于缩小窗口[left,right],直到窗
口中的字符串不在满足要求。每增加一次left,需要更新一次结果。
4. 重复第2和第3步,直到right到达字符串的尽头。
==============================================================================
完整代码如下:
public int lengthOfLongestSubstring(String s){ HashMap<Character,Integer> map = new HashMap<>(); int max = 0; //最长长度 int left = 0; //滑动窗口最初为零 for(int i = 0;i<s.length();i++){ if(map.containsKey(s.charAt(i))){ //如果包含,则更新left, left = Math.max(left,map.get(s.charAt(i)+1)); //之所以要不能直接取map.get(s.charAt(i))+1是因为当前值可能不包含在有效字段里面 } map.put(s.charAt(i),i);//更新left后,不管原来的 s.charAt(i) 是否在最长子段中,我们都要将 s.charAt(i) 的位置更新为当前的i, //如果包含了,则会把之前的给覆盖掉。 max = Math.max(max,i-left+1); //更新max } return max; }
2021-05-29