【力扣刷题实战】找到字符串中所有字母异位词

一、题目展示

二、代码解法

三、代码整体思路

四、代码详细解释

一、题目展示

二、代码解法

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        int slen=s.size(),plen=p.size();
        if(slen<plen)
        {
            return vector<int>();
        }
       vector<int> ans;
       vector<int> scont(26);
       vector<int> pcont(26);
       for(int i=0;i<plen;i++)
       {
        ++scont[s[i]-'a'];
        ++pcont[p[i]-'a'];
       }
       if(scont==pcont)
       {
        ans.emplace_back(0);
       }
       for(int i=0;i<slen-plen;i++)
       {
        --scont[s[i]-'a'];
        ++scont[s[i+plen]-'a'];
        if(scont==pcont)
        {
           ans.emplace_back(i+1);
        }
       }
       return ans;
    }
};

三、代码整体思路

这段 代码定义了一个名为 findAnagrams 的函数,它的主要功能是在字符串 s 中找出所有字符串 p 的异位词的起始索引。异位词指的是由相同字母重排列形成的字符串(包括相同的字符串)。

这段代码使用滑动窗口和字符频率统计的方法来解决问题。通过比较滑动窗口内字符的频率和目标字符串 p 中字符的频率,找出所有异位词的起始位置。下面我们逐行来详细解释这段代码。

四、代码详细解释

类和函数定义:

cpp 复制代码
class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
  • 定义了一个名为 Solution 的类,其中包含一个公共成员函数 findAnagrams
  • findAnagrams 函数接受两个字符串 sp 作为参数,并返回一个整数向量,该向量包含字符串 s 中所有 p 的异位词的起始索引。
处理边界情况:
cpp 复制代码
int sLen = s.size(), pLen = p.size();

if (sLen < pLen) {
    return vector<int>();
}
  • 首先获取字符串 sp 的长度,分别存储在变量 sLenpLen 中。
  • 如果字符串 s 的长度小于 p 的长度,说明 s 中不可能存在 p 的异位词,直接返回一个空的整数向量。

初始化变量:

cpp 复制代码
vector<int> ans;
vector<int> sCount(26);
vector<int> pCount(26);
  • ans:用于存储所有找到的异位词的起始索引。
  • sCount:一个长度为 26 的整数向量,用于统计滑动窗口内每个小写字母的出现频率。
  • pCount:一个长度为 26 的整数向量,用于统计字符串 p 中每个小写字母的出现频率。

scontpcont:它们都是长度为 26 的 vector<int> 类型的向量,用于分别记录字符串 sp 中每个小写字母的出现次数。因为小写字母 az 可以通过减去字符 'a' 的 ASCII 值映射到 0 到 25 的索引范围,所以使用长度为 26 的向量来存储每个字母的计数

初始化滑动窗口和目标字符串的字符频率:
  • 遍历字符串 p 的长度,同时更新 sCountpCount 向量。
  • s[i] - 'a'p[i] - 'a' 是将字符映射到 0 - 25 的索引,对应小写字母 az。例如,字符 'a' 映射到索引 0,'b' 映射到索引 1,以此类推。
  • 通过 ++sCount[s[i] - 'a']++pCount[p[i] - 'a'] 分别统计滑动窗口内和字符串 p 中每个字符的出现频率。
检查初始窗口是否为异位词:
cpp 复制代码
if (sCount == pCount) {
    ans.emplace_back(0);
}

这里的emplace_back 函数 是 std::vector 容器提供的成员函数 。它的作用是在 vector 的尾部直接构造新元素,而不是像 push_back 那样先创建一个临时对象,再将其拷贝或移动到 vector 尾部。这意味着在某些情况下(比如构造复杂对象时),emplace_back 能避免不必要的对象拷贝或移动操作,从而提高效率。

这个判断是比较 sCountpCount 向量是否相等。如果相等,说明字符串 s 的前 pLen 个字符组成的子串是 p 的异位词,将起始索引 0 添加到 ans 向量中。

滑动窗口移动:
cpp 复制代码
for (int i = 0; i < sLen - pLen; ++i) {
    --sCount[s[i] - 'a'];
    ++sCount[s[i + pLen] - 'a'];

    if (sCount == pCount) {
        ans.emplace_back(i + 1);
    }
}
  • 使用一个循环来移动滑动窗口,窗口的大小始终保持为 pLen
  • --sCount[s[i] - 'a']:将滑动窗口最左边的字符的频率减 1,表示该字符离开窗口。
  • ++sCount[s[i + pLen] - 'a']:将滑动窗口最右边的下一个字符的频率加 1,表示该字符进入窗口。
  • 每次移动窗口后,比较 sCountpCount 向量是否相等。如果相等,说明当前滑动窗口内的子串是 p 的异位词,将当前窗口的起始索引 i + 1 添加到 ans 向量中。
返回结果:
cpp 复制代码
return ans;
  • 最后返回存储所有异位词起始索引的 ans 向量。
相关推荐
不是仙人的闲人几秒前
算法之回溯法
开发语言·数据结构·c++·算法
小德乐乐6 分钟前
计算机软考中级 知识点记忆——排序算法 冒泡排序-插入排序- 归并排序等 各种排序算法知识点整理
数据结构·算法·排序算法
天天扭码41 分钟前
一分钟解决一道算法题——矩阵置零
前端·算法·面试
天天扭码1 小时前
偶遇天才算法题 | 拼劲全力,无法战胜 😓
前端·算法·面试
2401_878624791 小时前
opencv(双线性插值原理)
人工智能·算法·计算机视觉
小豪GO!2 小时前
数据结构-八大排序
数据结构·算法·排序算法
烟锁池塘柳02 小时前
【数学建模】随机森林算法详解:原理、优缺点及应用
算法·随机森林·数学建模
大龄门外汉2 小时前
数据结构之二叉树
c语言·数据结构·笔记·改行学it
极昆仑智慧2 小时前
多模态知识图谱:重构大模型RAG效能新边界
人工智能·算法·语言模型·自然语言处理·知识图谱
天天扭码2 小时前
面试官:算法题”除自身以外数组的乘积“ 我:😄 面试官:不能用除法 我:😓
前端·算法·面试