3. 無重復字符的最長子串
給定一個字符串 s
,請你找出其中不含有重復字符的 最長子串的長度。
思路:雙指針指向不含重復字符的連續字串的頭和尾,用集合存儲子串中的元素,有重復時,左指針持續右移,無重復后統計長度
class Solution {public int lengthOfLongestSubstring(String s) {int i = 0; // 左邊界int j = 0; // 右邊界int n = s.length();int len = 0; // 記錄最長不重復子串的長度if(n == 0){return 0;}// 使用 HashSet 來存儲當前窗口內的字符,用于快速判斷字符是否重復Set<Character> set = new HashSet<>();
?while(j < n){// 如果當前字符已經在窗口內,說明出現了重復字符// 需要移動左邊界 i,直到窗口內沒有重復字符為止while(set.contains(s.charAt(j))){set.remove(s.charAt(i));++i;}
?len = Math.max(j - i, len);set.add(s.charAt(j));++j;}// 因為在循環中計算長度時沒有加 1,所以這里需要加 1return len + 1;}
}
438. 找到字符串中所有字母異位詞
給定兩個字符串 s
和 p
,找到 s
中所有 p
的 異位詞 的子串,返回這些子串的起始索引。不考慮答案輸出的順序。
思路:維護一個固定長度的窗口,向后遍歷,每前進一步就檢查當前窗口是否滿足條件,滿足條件就記錄下來
class Solution {public List<Integer> findAnagrams(String s, String p) {// 獲取字符串 s 和 p 的長度int sLen = s.length(), pLen = p.length();
?// 如果 s 的長度小于 p 的長度,直接返回空列表// 因為 s 中不可能包含 p 的字母異位詞if (sLen < pLen) {return new ArrayList<Integer>();}
?// 初始化結果列表,用于存儲所有字母異位詞的起始索引List<Integer> ans = new ArrayList<Integer>();
?// 初始化兩個數組,分別用于統計 s 和 p 中字符的頻率int[] sCount = new int[26]; // 統計 s 中字符的頻率int[] pCount = new int[26]; // 統計 p 中字符的頻率
?// 初始化窗口,統計 s 的前 pLen 個字符和 p 中所有字符的頻率for (int i = 0; i < pLen; ++i) {++sCount[s.charAt(i) - 'a']; // 統計 s 的前 pLen 個字符++pCount[p.charAt(i) - 'a']; // 統計 p 中的所有字符}
?// 檢查初始窗口是否是 p 的字母異位詞// 如果兩個頻率數組相等,則說明 s 的前 pLen 個字符是 p 的字母異位詞if (Arrays.equals(sCount, pCount)) {ans.add(0); // 將起始索引 0 添加到結果列表中}
?// 使用滑動窗口遍歷 s,窗口大小固定為 pLenfor (int i = 0; i < sLen - pLen; ++i) {// 更新窗口:// 1. 移除窗口左邊界字符的計數--sCount[s.charAt(i) - 'a'];// 2. 添加窗口右邊界字符的計數++sCount[s.charAt(i + pLen) - 'a'];
?// 檢查當前窗口是否是 p 的字母異位詞if (Arrays.equals(sCount, pCount)) {ans.add(i + 1); // 如果是,將當前窗口的起始索引添加到結果列表中}}
?// 返回結果列表return ans;}
}