指標的靈活應用--核心連結串列中的container_of
阿新 • • 發佈:2020-11-05
問題描述
給定一個字串,找出不含有重複字元的最長子串的長度。
解法一:
建立一個 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++; } }