无重复字符的最长子串
问题描述
给定一个字符串,找出不含有重复字符的最长子串的长度。
解法一:
创建一个 pre 数组表示长度,从左到右遍历字符串数组。
public static int lengthOfLongestSubstringMethod(String s){ // 数组没有赋值的时,所有元素会初始化为 0 // 字符为下标时,会将 ASCII 码作为下标 int[] pre = new int[128]; int ans = 0; int left = 0; // i 表示当前处理的第 i 个字符 for (int i = 0; i < s.length(); i++) { // c 为依次取出的单个字符 char c = s.charAt(i); //如果 pre[c] 不等于 0 表示数组中该位置被修改过,也就代表前面有重复字符 if (pre[c]!=0 && pre[c] > left){ // 更新 ans 最大值 // i - left重复元素下标 - 上一次没重复的下标 ans = Math.max(ans,i-left); // left 是为求下一个子串长度做准备,因为要求出的是最长的子串长度 // 更新 left,上一次没重复的下标 left=pre[c]; } // 如果 pre[c] 为 0,或者 pre[c] <= t pre[c] = i + 1; } return Math.max(ans, s.length() - left); }
解法二:
定义一个Set去保存是否有重复字符。
public static int lengthOfLongestSubstringMethod1(String s) { Set<Character> set =new HashSet<>(); int left =0,right = 0,max=0; while (right<s.length()){ if (set.contains(s.charAt(right))){ //移除左端口的数据 set.remove(s.charAt(left)); //左窗口右移 left++; }else{ //添加数据并且窗口右移 set.add(s.charAt(right)); right++; //比较多次set里面保存数据最多的值 max=Math.max(max,set.size()); } } return max; }
总结:
滑动窗口算法复杂度是O ( n ) 比暴力解要高效很多。可以看到算法是维护一个窗口,最关键的点就是何时使右边界向右移动使得窗口扩张和何时使左边界向右移动使得窗口收缩。
算法大概逻辑如下:
//定义左右窗口 int left = 0, right = 0; while (right < s.size()) { // 增大窗口 window.add(s[right]); right++; while (window needs shrink) { // 缩小窗口 window.remove(s[left]); left++; } }