【LeetCode Hot100 滑动窗口】无重复字符的最长子串、找到字符串中所有字母异位词

滑动窗口

    • 1. 无重复字符的最长子串
      • 题目描述
      • 解题思路
        • 步骤:
        • 时间复杂度:
        • 空间复杂度:
      • 代码实现
    • 2. 找到字符串中所有字母异位词
      • 题目描述
      • 解题思路
        • 步骤:
        • 时间复杂度:
        • 代码实现

1. 无重复字符的最长子串

题目描述

给定一个字符串 s,请你找出其中不含有重复字符的最长子串的长度。

解题思路

这个问题可以通过 滑动窗口 的技巧来解决。我们用两个指针,ij,构成一个滑动窗口,并利用哈希表来记录窗口中出现的字符。

步骤:
  1. 初始化

    • max 记录当前最长无重复子串的长度。
    • map 是一个哈希表,用来存储字符及其对应的最新位置,确保窗口内没有重复字符。
    • j 是窗口的起始位置,i 是当前窗口的结束位置。
  2. 滑动窗口

    • 遍历字符串 s,每次扩展窗口的右边界(i),并检查当前字符是否在窗口中已经存在。
    • 如果当前字符已经存在于窗口内(即哈希表中),说明需要更新窗口的左边界 j,通过移动 j 来删除窗口左侧的字符,直到窗口内没有重复字符为止。
    • 每次更新窗口后,计算当前无重复字符子串的长度并更新最大长度 max
  3. 返回结果

    • 最后返回最长无重复子串的长度 max
时间复杂度:
  • 时间复杂度为 O(n),其中 n 是字符串 s 的长度。每个字符只被访问一次,哈希表的操作是常数时间复杂度 O(1)
空间复杂度:
  • 空间复杂度为 O(min(n, m)),其中 n 是字符串的长度,m 是字符集的大小。哈希表最多存储字符集中的所有字符。

代码实现

class Solution {
    public int lengthOfLongestSubstring(String s) {
        int max = 0; // 表示最大长度
        Map<Character, Integer> map = new HashMap<>(); // 滑动窗口
        int j = 0;
        for (int i = 0; i < s.length(); i++) {
            while (map.containsKey(s.charAt(i))) {
                // 如果当前字符已存在,更新窗口的左边界
                map.remove(s.charAt(j));
                j++;
            }
            // 将当前字符加入哈希表
            map.put(s.charAt(i), 1);
            // 更新最大长度
            max = Math.max(max, i - j + 1);
        }
        return max;
    }
}

2. 找到字符串中所有字母异位词

题目描述

给定一个字符串 s 和一个字符串 p,找到 s 中所有 p 的字母异位词的起始索引,并返回这些索引的列表。

字符串 p 的字母异位词是指字符串 p 的字符重新排列组成的字符串。字符串 s 中的字母异位词是指 p 的任意排列出现在 s 中的子串。

解题思路

我们可以通过 滑动窗口 的方法来高效地解决此问题。具体来说,目标是检查字符串 s 中每个长度为 p.length() 的子串是否是 p 的字母异位词。为此,我们需要用到字符频率计数器来比较每个子串与 p 中字符的频率。

步骤:
  1. 初始化

    • 首先,我们定义两个频率数组 sCntpCnt,分别用来记录字符串 sp 中每个字符的出现频率。
    • sCnt[i] 表示字符 i 在字符串 s 中的频率,pCnt[i] 表示字符 i 在字符串 p 中的频率。
  2. 滑动窗口

    • 通过滑动窗口的方式遍历字符串 s,窗口大小为 p.length()。每次滑动窗口时,更新 sCnt 中对应字符的频率。
    • 在每次滑动时,我们将窗口的左边界字符频率减去,右边界字符频率加上,保证 sCnt 始终记录窗口内的字符频率。
  3. 比较

    • 每次更新窗口后,比较 sCntpCnt 是否相同,如果相同,则说明当前窗口内的子串是 p 的字母异位词,记录当前索引。
  4. 返回结果

    • 返回所有满足条件的起始索引。
时间复杂度:
  • 时间复杂度为 O(n),其中 n 是字符串 s 的长度。每次滑动窗口的操作时间为 O(1),总共滑动 n - m + 1 次。
  • 空间复杂度为 O(1),因为我们只用了两个长度为 26 的数组来存储字符频率。
代码实现
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        int n = s.length(), m = p.length();
        List<Integer> res = new ArrayList<>();
        int[] sCnt = new int[26];
        int[] pCnt = new int[26];

        if (n < m) {
            return res;
        }
        for (int i = 0; i < m; i++) {
            pCnt[p.charAt(i) - 'a']++;
            sCnt[s.charAt(i) - 'a']++;
        }
        // 刚开始的位置
        if(Arrays.equals(sCnt, pCnt)){
            res.add(0);
        }
        // 开始滑动窗口
        for (int i = m; i < n; i++) {
            sCnt[s.charAt(i) - 'a']++;
            sCnt[s.charAt(i - m) - 'a']--;
            if (Arrays.equals(sCnt, pCnt)) {
                res.add(i - m + 1);
            }
        }
        return res;
    }
}

你可能感兴趣的:(数据结构与算法,leetcode,算法,职场和发展)