【LeetCode-滑动窗口-中等】无重复字符的最长字符串
这道题是这样的,在一个给定的字符串中,要求你来找到不含有重复字符的最长子串的长度
比如 str = "abcabcbb" 没有重复字符的最长子串是 abc 所以长度为3
又比如 str = "abpwkewba" 没有重复字符的最长子串是 abpwke 所以长度为6
这个题目的解答,涉及到算法中的滑动窗口,滑动窗口的这个滑动的意思是 窗口的大小是可变的。滑动窗口有一个很重要的特性: 窗口的左边界和右边界都只能向右移动,而不能向左移动 =》 这是为了保证滑动窗口的时间复杂度是O(N). 如果窗口的左右边界向左移动的话,这个叫做 "回溯", 这样的话,时间的复杂度可能超过O(N)
滑动窗口经常用来求解满足某种条件的某段连续区间的最短或最长子序列(一般为子数组,子字符串等),包括 最小摘要,和大于给定目标值的最短子序列,无重复字符的最长子串,有k个不同字符的子串等。滑动窗口被认为是一种特殊的双指针
我们来看看,我们自己是怎么想的, 以字符串 str = "abcabcbb" 为例,要找出没有重复的最长子串:
从第1个字符a开始 (a)bcabcbb, 最长无重复子串为 (abc)abcbb => abc
从第2个字符b开始 a(b)cabcbb, 最长无重复子串为 a(bca)bcbb => bca
从第3个字符b开始 ab(c)abcbb, 最长无重复子串为 ab(cab)cbb => cab
从第4个字符a开始 abc(a)bcbb, 最长无重复子串为 abc(abc)bb => abc
从第5个字符b开始 abca(b)cbb, 最长无重复子串为 abca(bc)bb => bc
从第6个字符c开始 abcab(c)bb, 最长无重复子串为 abcab(cb)b => cb
从第7个字符b开始 abcabc(b)b, 最长无重复子串为 abcabc(b)b => b
从第8个字符b开始 abcabcb(b), 最长无重复子串为 abcabcb(b) => b
从这个过程和结果,我们是不是可以想到这就像是一个滑动窗口,这个滑动窗口的左右指针都在向右边移动,过程为 abc -> bca -> cab -> abc -> bc -> cb -> b -> b
所以这个过程就是,往右移动一次左指针,然后右指针也往右移动,直到左右指针之间的子字符串出现相同的字符时,停止移动右指针,这就是这一轮的最大子串。
C#代码如下
1 public int lengthOfLongestSubString(string str) 2 { 3 var rtrSet = new HashSet<char>(); 4 int len = str.Length; 5 6 // 初始化右指针,初始值为 -1, 相当于在字符串第一个起始位置0位置的左侧,还没有开始移动 7 //初始化返回值 rtrLen为0 8 int rightPoint = -1, rtrLen = 0; 9 10 for (int leftPoint = 0; leftPoint < len; leftPoint++) 11 { 12 //左指针往右移动一位,所以要从集合中移除左指针往右移动前指向的这个字符 13 if (leftPoint != 0) 14 { 15 rtrSet.Remove(str[leftPoint - 1]); 16 } 17 18 //右指针往右移动,只要集合中不包括当前右指针指向的字符,右指针就往右移动,一旦发现集合中存在当前右指针指向的字符,就马上停止移动右指针 19 while (rightPoint + 1 < len && !rtrSet.Contains(str[rightPoint + 1])) 20 { 21 rtrSet.Add(str[rightPoint + 1]); 22 ++rightPoint; 23 } 24 25 rtrLen = Math.Max(rtrLen, (rightPoint - leftPoint + 1)); 26 } 27 28 29 return rtrLen; 30 31 }
浙公网安备 33010602011771号