哈希算法题目:字符串的排列
字数 941 2025-10-27 11:27:25

哈希算法题目:字符串的排列

题目描述:给定两个字符串 s1 和 s2,判断 s2 是否包含 s1 的排列。如果是,返回 true;否则,返回 false。换句话说,第一个字符串的排列之一是第二个字符串的子串。

解题过程:

  1. 问题理解
    我们需要判断s2中是否包含一个子串,这个子串是s1的某个排列。这意味着这个子串和s1包含完全相同的字符,且每个字符的出现次数也相同,只是顺序可能不同。

  2. 核心思路
    使用滑动窗口配合哈希表(字符频率统计)来解决:

  • 统计s1中每个字符的出现频率
  • 在s2上维护一个与s1长度相同的滑动窗口
  • 统计窗口中每个字符的出现频率
  • 比较两个频率统计是否相同
  1. 详细步骤

步骤1:特殊情况处理
如果s1的长度大于s2,s2不可能包含s1的排列,直接返回false。

步骤2:初始化频率数组
创建两个大小为26的数组(假设只包含小写字母):

  • s1Count:记录s1中每个字符的频率
  • s2Count:记录s2当前窗口中每个字符的频率

步骤3:统计初始频率
首先统计s1所有字符的频率,同时统计s2前n个字符的频率(n为s1的长度)。

步骤4:比较初始窗口
比较s1Count和s2Count是否完全相同。如果相同,说明找到排列,返回true。

步骤5:滑动窗口遍历
从位置n开始遍历s2的剩余部分:

  • 移除窗口最左边的字符(索引为i-n)
  • 添加新进入窗口的字符(索引为i)
  • 每次滑动后比较两个频率数组

步骤6:优化比较
为了避免每次都比较整个数组,可以维护一个匹配计数器,记录当前有多少个字符的频率是匹配的。

  1. 具体实现示例

以s1 = "ab", s2 = "eidbaooo"为例:

初始化:

  • s1Count: a→1, b→1, 其他→0
  • 初始窗口"ei":e→1, i→1, 其他→0
  • 匹配字符数:0(没有字符频率匹配)

滑动过程:
窗口1:"ei" → 不匹配
窗口2:"id" → 不匹配
窗口3:"db" → 不匹配
窗口4:"ba" → a→1, b→1,与s1Count完全匹配,返回true

  1. 算法复杂度
  • 时间复杂度:O(n),其中n是s2的长度
  • 空间复杂度:O(1),因为使用固定大小的数组

这种方法通过滑动窗口和频率统计,高效地解决了字符串排列的检测问题。

哈希算法题目:字符串的排列 题目描述:给定两个字符串 s1 和 s2,判断 s2 是否包含 s1 的排列。如果是,返回 true;否则,返回 false。换句话说,第一个字符串的排列之一是第二个字符串的子串。 解题过程: 问题理解 我们需要判断s2中是否包含一个子串,这个子串是s1的某个排列。这意味着这个子串和s1包含完全相同的字符,且每个字符的出现次数也相同,只是顺序可能不同。 核心思路 使用滑动窗口配合哈希表(字符频率统计)来解决: 统计s1中每个字符的出现频率 在s2上维护一个与s1长度相同的滑动窗口 统计窗口中每个字符的出现频率 比较两个频率统计是否相同 详细步骤 步骤1:特殊情况处理 如果s1的长度大于s2,s2不可能包含s1的排列,直接返回false。 步骤2:初始化频率数组 创建两个大小为26的数组(假设只包含小写字母): s1Count:记录s1中每个字符的频率 s2Count:记录s2当前窗口中每个字符的频率 步骤3:统计初始频率 首先统计s1所有字符的频率,同时统计s2前n个字符的频率(n为s1的长度)。 步骤4:比较初始窗口 比较s1Count和s2Count是否完全相同。如果相同,说明找到排列,返回true。 步骤5:滑动窗口遍历 从位置n开始遍历s2的剩余部分: 移除窗口最左边的字符(索引为i-n) 添加新进入窗口的字符(索引为i) 每次滑动后比较两个频率数组 步骤6:优化比较 为了避免每次都比较整个数组,可以维护一个匹配计数器,记录当前有多少个字符的频率是匹配的。 具体实现示例 以s1 = "ab", s2 = "eidbaooo"为例: 初始化: s1Count: a→1, b→1, 其他→0 初始窗口"ei":e→1, i→1, 其他→0 匹配字符数:0(没有字符频率匹配) 滑动过程: 窗口1:"ei" → 不匹配 窗口2:"id" → 不匹配 窗口3:"db" → 不匹配 窗口4:"ba" → a→1, b→1,与s1Count完全匹配,返回true 算法复杂度 时间复杂度:O(n),其中n是s2的长度 空间复杂度:O(1),因为使用固定大小的数组 这种方法通过滑动窗口和频率统计,高效地解决了字符串排列的检测问题。