算法 - 字符串 - 面试 求一个字符串的最大不重复子串 - 滑动窗口
这是我面试时的一道算法题,题目是这样的
// 获取字符串的不重复最大字串 比如
abbbbbbcd 返回 bcd
abefbca 返回 efbca
这道题怎么做呢,这道算法题要用滑动窗口来做
我们设定一个窗口 [left, right]
我们先看最完美的情况,字符串中都不重复
abcde 这种情况 滑动窗口 [left,right] left =0 字符串第1个下标 ,right 就是一个一个字符往右边走,逐步加1,也就是循环。 所以结果就是
滑动窗口 [0,0] => a
滑动窗口 [0,1] => ab
滑动窗口 [0,2] => abc
滑动窗口 [0,3] => abcd
滑动窗口 [0,4] => abcde
显然,上面5个滑动窗口中最长的结果就是 最后一个 => abcde
那如果存在重复呢,我们来看
abcbef 这个例子
滑动窗口 [0,0] => a
滑动窗口 [0,1] => ab
滑动窗口 [0,2] => abc
滑动窗口 [0,3] => abcb => 这里出现了重复,所以这个滑动窗口不行,为了不重复,它只能是cb,那么滑动窗口的左边是2 => [2,3] = cb
滑动窗口 [2,3] 出 => cb
滑动窗口 [2,4] => cbe
滑动窗口 [2,5] => cbef
结果,上面6个滑动窗口中,最长的是cbef
发现规律没,也就是说,滑动窗口左边的初始值left =0, 滑动窗口右边的值right 就是一个一个循环下标0,1,2,....
如果循环过程中,一旦发现哪一个字符在之前出现过,那么要更改什么 ? => 更改滑动窗口的左边值left, 把left值更新为 这个字符上一次出现位置k的下一个位置 ,也就是 left = k + 1 形成新的窗口左值,继续后面的循环
上面例子中, 原始滑动窗口[0,3] = abcb 这个时候下标循环到3,字符是b,但发现这个字符之前出现过,上一次出现的位置是1, 所以我们要更新这个滑动窗口的left, left = 1 + 1 = 2, 所以这里窗口应该变成[2,3] = cb
所以这个题目的关键在2步
1. 发现重复字符时,更新滑动窗口的左值left => 这里我们需要知道这个重复字符上一次出现的位置,我们可以用Dictionary来保存字符串中每种字符最新出现的位置
2. 把每一次滑动窗口的值记下来,取字符个数最多的那个值,就是我们要的结果
比如 abca 这里我们用一个Dictionary来保持字符位置
Dictionary<key,value>() {
[a,0], - a出现的位置是0
[b,1], - b 出现的位置是1
[c,1] - c出现的位置是2
} 当循环到第3个位置,发现是a,它在Dictionary里面已经有了,里面的位置是0,现在位置是3,所以把位置更新成最近的位置3
Dictionary<key,value>() {
[a,3], - a最近出现的位置是3
[b,1], - b 出现的位置是1
[c,1] - c出现的位置是2
}
好了,代码如下
using System; using System.Collections.Generic; public class Solution { /// <summary> /// 最长无重复字符子串 /// </summary> public static string LongestUniqueSubstring(string s) { // key:字符,value:字符最近出现的下标 Dictionary<char, int> map = new Dictionary<char, int>(); int left = 0; // 窗口左边界 int maxLength = 0; // 记录最长子串长度 int startPos = 0; // 最长子串起始位置 // right 窗口右边界,不断向右扩张 for (int right = 0; right < s.Length; right++) { char c = s[right]; // 字符在窗口内已经出现过,移动左边界到重复字符下一位 if (map.ContainsKey(c) && map[c] >= left) { left = map[c] + 1; //出现重复字符,把窗口左边界left的值更新为重复字符上一次位置+ 1 } // 更新字符最新位置 map[c] = right; //更新Dictionary里面该重复字符最近一次的位置 // 判断当前窗口是否更长,更新最大值 int currentLen = right - left + 1; if (currentLen > maxLength) { maxLength = currentLen; startPos = left; } } // 截取最长无重复子串 return s.Substring(startPos, maxLength); } public static void Main() { string test = "abbbbbbcd"; string ans = LongestUniqueSubstring(test); Console.WriteLine(ans); // 输出 bcd } }
浙公网安备 33010602011771号