算法打卡第九天

31.找出字符串中第一个匹配项的下标

(力扣28题)

给你两个字符串 haystackneedle ,请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle 不是 haystack 的一部分,则返回 -1

示例 1:

输入:haystack = "sadbutsad", needle = "sad"
输出:0
解释:"sad" 在下标 0 和 6 处匹配。
第一个匹配项的下标是 0 ,所以返回 0 。

示例 2:

输入:haystack = "leetcode", needle = "leeto"
输出:-1
解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。

提示:

  • 1 <= haystack.length, needle.length <= 104

  • haystackneedle 仅由小写英文字符组成

  • 解题思路

  1. 构造 next 数组
    • 使用 getNext 函数生成 needle 的部分匹配表(next 数组)。next[i] 表示 needle 的前 i 个字符中,最长相同前缀和后缀的长度。
    • 通过双指针 iji 遍历字符串,j 表示当前匹配的前缀长度。如果当前字符不匹配,则通过 next[j - 1] 回退,直到找到匹配的前缀或回退到0。
  2. 匹配过程
    • strStr 函数中,使用 next 数组辅助匹配。
    • 遍历 haystack,用指针 j 记录当前匹配到 needle 的位置。
    • 如果当前字符不匹配且 j > 0,则通过 next[j - 1] 回退。
    • 如果匹配成功,j 增加;如果 j 达到 needle.size(),说明找到完整匹配,返回起始位置。
    • 如果遍历完 haystack 仍未找到匹配,返回 -1

关键点

  • next 数组的生成是 KMP 算法的核心,它帮助快速跳过已匹配的部分,避免重复比较。
  • 匹配过程中利用 next 数组实现高效回退,减少不必要的字符比较。
class Solution
{
public:
    void getNext(int *next, const string &s)
    {
        // 初始化
        int j = 0;                         //  j指向前缀末尾位置
        next[0] = 0;                       // 构造next数组,前缀表
        for (int i = 1; i < s.size(); i++) // ,i指向后缀末尾位置
        {
            // 前后缀不同
            while (j > 0 && s[i] != s[j])
            {
                j = next[j - 1 ];// 向前回退
            }
            // 处理前后缀相同的情况
            if (s[i] == s[j])
            {

                j++;
            }
            // // 将j(前缀的长度)赋给next[i]
            next[i] = j;
        }
    }
    int strStr(string haystack, string needle)
    {
        // needle为空
        if (needle.size() == 0)
        {
            return 0;
        }

        // 初始化 next 数组,用于存储 needle 的部分匹配表
        vector<int> next(needle.size());
        // / 构造 next 数组
        getNext(&next[0], needle);
        // j 用于记录当前匹配到 needle 的位置
        int j = 0;
        //   // 遍历 haystack
        for (int i = 0; i < haystack.size(); ++i)
        {
            //    // 如果当前字符不匹配,并且 j > 0,说明可以回退
            while (j > 0 && haystack[i] != needle[j])
            {
                // 回退到 next[j-1] 的位置
                j = next[j - 1]; // 向前回退
            }
            // 如果当前字符匹配
            if (haystack[i] == needle[j])
            {
                j++;
            }
            // 如果 j 达到 needle 的长度,说明找到了完整的 needle
            if (j == needle.size())
            {
                // 返回 needle 在 haystack 中的起始位置
                return (i - needle.size() + 1);
            }
        }
        // 如果遍历完 haystack 也没有找到 needle,返回 -1
        return -1;
    }
};
  • 时间复杂度: O(n + m)
  • 空间复杂度: O(m)

32.右旋字符串

(卡码网55题)

题目描述

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。

例如,对于输入字符串 “abcdefg” 和整数 2,函数应该将其转换为 “fgabcde”。

输入:输入共包含两行,第一行为一个正整数 k,代表右旋转的位数。第二行为字符串 s,代表需要旋转的字符串。

输出:输出共一行,为进行了右旋转操作后的字符串。

样例输入:

2
abcdefg 

样例输出:

fgabcde

数据范围:1 <= k < 10000, 1 <= s.length < 10000;

代码

#include <iostream>
#include <algorithm>
using namespace std;
int main()
{
    int n = 0;
    string s = "";
    cin >> n;
    cin >> s;
    // 整体反转
    reverse(s.begin(), s.end());
    // 前一段反转
    reverse(s.begin(), s.begin() + n);
    // 后一段反转
    reverse( s.begin() + n, s.end());
    cout << s << endl;
    return 0;
}
  • 时间复杂度: O(len) len是字符串的长度
  • 空间复杂度: O(1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值