來源:力扣(LeetCode)
連接:https://leetcode-cn.com/problems/longest-substring-without-repeating-charactersjava
給定一個字符串,請你找出其中不含有重複字符的 最長子串 的長度。數組
示例 1:數據結構
輸入: "abcabcbb" 輸出: 3 解釋: 由於無重複字符的最長子串是 "abc",因此其長度爲 3。
示例 2:ui
輸入: "bbbbb" 輸出: 1 解釋: 由於無重複字符的最長子串是 "b",因此其長度爲 1。
示例 3:code
輸入: "pwwkew" 輸出: 3 解釋: 由於無重複字符的最長子串是 "wke",因此其長度爲 3。 請注意,你的答案必須是 子串 的長度,"pwke" 是一個子序列,不是子串。
Java 數組的下標能夠是:leetcode
例如:字符串
int a[300],i;
// 下標是整型常量,整數 5 a[5] = 5; // 下標是整型變量, i 如今數值 5, 就是數組元素 a[5]。 i = 5; a[i] = 5; // 下標是整型字符常量,等於 F 的 ASCII 碼值,就是數組元素 a[70]。 a['F'] = 5; // 下標是整型表達式,表達式運算結果是 5,就是數組元素 a[5]。 a['F' - 'A'] = 5;
怎麼查看 ASCII 碼的值?get
// 好比查看 a 的 ASCII 值 System.out.println((int)'a'); // 結果爲 97 System.out.println((int)'z'); // 結果爲 122
import java.util.HashMap; import java.util.Map; /** * <p> * 03:給定一個字符串,請你找出其中不含有重複字符的最長子串的長度。 * * @author XiaoPengwei * @since 2019-07-14 */ public class LC03LongestSubstring { public static void main(String[] args) { // 該表明性示例,最長爲 4,即 abcd // String str = "abcabcdbcs"; String str = "abba"; int lengthByMethod1 = lengthOfLongestSubstringMethod1(str); System.out.println("lengthByMethod1-->" + lengthByMethod1); int lengthByMethod2 = lengthOfLongestSubstringMethod2(str); System.out.println("lengthByMethod2-->" + lengthByMethod2); } /** * 方法一: * 求不含有重複字符的最長子串的長度 * 思路:建立一個 pre 數組表示長度,從左到右遍歷字符串數組,查看 * * @param s 字符串參數 * @return int 長度 */ public static int lengthOfLongestSubstringMethod1(String s) { // 數組沒有賦值的時,全部元素會初始化爲 0 // 字符爲下標時,會將 ASCII 碼做爲下標 int[] pre = new int[128]; int max = 0, t = 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] > t) { // 更新 max 最大值 // i - t 重複元素下標 - 上一次沒重複的下標 max = Math.max(max, i - t); // t 是爲求下一個子串長度作準備,由於要求出的是最長的子串長度 // 更新 t,上一次沒重複的下標 t = pre[c]; } // 若是 pre[c] 爲 0,或者 pre[c] <= t pre[c] = i + 1; } return Math.max(max, s.length() - t); } /** * 方法二: * 定義一個 map 數據結構存儲 (k, v),其中 key 值爲字符,value 值爲字符位置 +1,加 1 表示從字符位置後一個纔開始不重複 * 咱們定義不重複子串的開始位置爲 start,結束位置爲 end; [start, end] 可理解爲滑動窗口 * 隨着 end 不斷遍歷向後,會遇到與 [start, end] 區間內字符相同的狀況,此時將字符做爲 key 值,獲取其 value 值,並更新 start,此時 [start, end] 區間內不存在重複字符 * 不管是否更新 start,都會更新其 map 數據結構和結果 max。 * 時間複雜度:O(n) * * @param s 字符串參數 * @return int 長度 * @author guanpengchn * @link https://leetcode-cn.com/problems/two-sum/solution/hua-jie-suan-fa-3-wu-zhong-fu-zi-fu-de-zui-chang-z/ */ public static int lengthOfLongestSubstringMethod2(String s) { // max 表示所求的最大長度 int max = 0; /* Map 中 key 值爲字符,value 值爲字符位置 +1,加 1 表示從字符位置後一個纔開始不重複 * 同一個字符 key,在 map 中只存在一個。當重複時更新它的值。 */ Map<Character, Integer> map = new HashMap<Character, Integer>(); /* start 指向不重複子串的第一個字符的下標。 * 當存在重複字符時 start 指向後面一個重複字符,指向下一個不重複子串的第一個字符的下標 */ for (int start = 0, end = 0; end < s.length(); end++) { char c = s.charAt(end); if (map.containsKey(c)) { /* 若是含有重複字符串,將滑動窗戶的開始位置更新,後移 * map.get(c) 的值表示該出現重複的字符,上一次出現時下標+1 * 何時會出現 start<map.get(c)? * 答:map.get(c) 該重複字符出現的位置不必定,若是重複字符出現的順序和以前同樣, * 好比:abcabcd,先重 a,再重 b * 何時會出現 start>map.get(c)? * 答:第二次出現重複時,若是重複的字符在第一次出現重複的字符前面 * 好比 abba,先重 b,再重 a。出現 a 重複時,start 爲 2 > map.get('a') 爲 1 */ start = Math.max(map.get(c), start); } /* 無論是否重複這裏都會執行 * 每次執行判斷一次滑動窗口長度是否超過當前最大長度,是則更新 * end - start + 1 表示滑動窗口長度,子串長度,不重複子串最短也爲 1 * 爲何要 + 1? * 當 start 和 end 指向一個是元素時,下標同樣,end-start 爲 0,此時存在一個不重複子串爲 1 個元素 * 當 end 指向 start 後面相鄰一個,end-start 爲 1,此時不重複子串爲 2 個元素 */ max = Math.max(max, end - start + 1); /* 無論是否重複這裏都會執行 * 若是不重複,會新添加一個 key,值爲:位置下標+1 * 若是重複,會更新這個 key 對應的值爲:後面又重複出現的該字符的位置下標+1 */ map.put(c, end + 1); } return max; } }