首页 > 编程语言 >Leetcode算法训练日记 | day9

Leetcode算法训练日记 | day9

时间:2024-03-30 23:33:40浏览次数:13  
标签:匹配 day9 needle next 算法 数组 字符串 haystack Leetcode

一、实现strStr函数

1.题目

Leetcode:第 28 题
给你两个字符串 haystack 和 needle ,请你在 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

2.解题思路

使用KMP算法,先计算next数组,该数组用于在字符串匹配中跳过已经知道的不匹配前缀,
 再根据next数组遍历模式串和字符串,直到找到完全匹配的字符串,并返回第一个匹配项的下标。

3.实现代码

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class Solution 
{
public:
    // getNext函数用于计算KMP算法的next数组,
    // 该数组用于在字符串匹配中跳过已经知道的不匹配前缀
    void getNext(vector<int>&next, const string& s) 
    {
        int j = 0; // 初始化j为0,表示当前没有匹配的前缀和后缀
        next[0] = 0; // 对于模式串的第一个字符,next数组的第一个值设为0
        for (int i = 1; i < s.size(); i++)  // 从模式串的第二个字符开始遍历
        {
            // 当前缀和后缀不匹配时,根据next数组回溯到上一个匹配的位置
            while (j > 0 && s[i] != s[j]) 
            {
                j = next[j - 1];
            }

            // 如果前缀和后缀匹配,j向前移动到下一个位置
            if (s[i] == s[j]) 
            {
                j++;
            }
           
            next[i] = j; // 记录当前位置的前缀和后缀的最长匹配长度
        }
    }

    // strStr函数使用KMP算法在字符串haystack中查找子字符串needle的起始索引
    int strStr(string haystack, string needle) 
    {
        // 如果needle为空字符串,直接返回0,表示找到了匹配(空字符串可以在任何位置开始)
        if (needle.size() == 0) 
        { 
            return 0;
        }
        
        vector<int> next(needle.size());// 分配next数组,用于存储needle的next值
        getNext(next, needle); // 计算needle的next数组
       
        int j = 0; // 初始化j为0,表示当前没有匹配的前缀和后缀

        for (int i = 0; i < haystack.size(); i++) // 遍历haystack中的每个字符
        { 
            // 当haystack中的字符与needle中的前缀和后缀不匹配时,根据next数组回溯
            while (j > 0 && haystack[i] != needle[j]) 
            {
                j = next[j - 1];
            }

            // 如果当前字符匹配,j向前移动到下一个位置
            if (haystack[i] == needle[j]) 
            {
                j++;
            }

            // 如果j等于needle的长度,表示找到了匹配
            if (j == needle.size()) 
            {
                // 返回匹配的起始索引,即i减去needle的长度再加1
                return (i - needle.size() + 1);
            }
        }
        // 如果遍历完haystack后没有找到匹配,返回-1
        return -1;
    }
};

//测试
int main()
{
    Solution s;
    string haystack = "abcsadbutsad";
    string needle = "sad";
    cout <<  "haystack = " << haystack << endl;
    cout << "needle = " << needle << endl;
    cout <<"在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标:"<<s.strStr(haystack,needle) << endl;
    cout <<endl;
    return 0;
}

二、重复的子字符串

1.题目

Leetcode:第 459 题
给定一个非空的字符串s ,检查是否可以通过由它的一个子串重复多次构成。

示例 1:
输入: s = "abab"
输出: true
解释: 可由子串 "ab" 重复两次构成。

示例 2:
输入: s = "aba"
输出: false

示例 3:
输入: s = "abcabcabcabc"
输出: true
解释: 可由子串 "abc" 重复四次构成。 (或子串 "abcabc" 重复两次构成。)

2.解题思路

使用KMP算法,先计算next数组,检查next数组的最后一个值不为0,则说明字符串有最长相同的前后缀,并且当s的长度可以被(s的长度 - 最长相等前后缀的长度), 即第一个重复长度整除时,说明字符串可以由子串重复多次构成。

3.实现代码
#include <iostream>
#include <vector>
using namespace std;

class Solution {
public:
    // getNext函数用于计算字符串s的next数组,该数组用于KMP算法中的部分匹配表
    void getNext(vector<int>&next, const string& s) 
    {
        int j = 0; // 初始化j为0,表示当前没有匹配的前缀和后缀
        next[0] = 0; // 对于字符串的第一个字符,next数组的第一个值设为0
        for (int i = 1; i < s.size(); i++) // 从字符串的第二个字符开始遍历
        { 
            while (j > 0 && s[i] != s[j]) 
            { 
                j = next[j - 1];// 当前缀和后缀不匹配时,根据next数组回溯
            }
            if (s[i] == s[j]) 
            { 
                j++;// 如果前缀和后缀匹配,j向前移动到下一个位置
            }
            next[i] = j; // 记录当前位置的前缀和后缀的最长匹配长度
        }
    }

    // repeatedSubstringPattern函数用于检查字符串s是否可以由其某个子字符串重复构成
    bool repeatedSubstringPattern(string s) 
    {
        if (s.size() == 0) // 如果字符串为空,直接返回false
        { 
            return false;
        }

        vector<int> next(s.size()); // 创建next数组,用于存储计算结果
        getNext(next, s); // 调用getNext函数计算next数组
        int len = s.size(); // 获取字符串s的长度

        // 检查next数组的最后一个值不为0,则说明字符串有最长相同的前后缀
        // 并且s的长度可以被(s的长度-最长相等前后缀的长度),即第一个重复长度,整除
        if (next[len - 1] != 0 && len % (len - (next[len - 1])) == 0)
        {
            return true; // 如果满足条件,说明s可以由其某个子字符串重复构成
        }
        return false; // 否则,s不能由其某个子字符串重复构成
    }
};

//测试
int main()
{
    Solution p;
    string s = "abab";
    cout << "s = " <<s<< endl;
    if (p.repeatedSubstringPattern(s))
    {
        cout <<s<<"可以由它的一个子串重复多次构成。" << endl;
    }
    else
    {
        cout << s << "不可以由它的一个子串重复多次构成。" << endl;
    }
    cout <<endl;
    return 0;
}

ps:以上皆是本人在探索算法世界旅途中的浅薄见解,诚挚地希望得到各位的宝贵意见与悉心指导,若有不足或谬误之处,还请多多指教。

标签:匹配,day9,needle,next,算法,数组,字符串,haystack,Leetcode
From: https://blog.csdn.net/m0_74882777/article/details/137184744

相关文章

  • 数据结构与算法——双向链表的使用原理
    双向链表是一种特殊链表,每个节点包含两个指针,一个指向前一个节点,一个指向后一个节点。双向链表可以支持双向遍历,插入和删除操作更加高效。双向链表的基本操作包括插入、删除、查找等。双向链表的常见应用场景包括LRU缓存淘汰算法、双向队列等需要频繁在两端进行操作的场景......
  • (算法)Lake Counting <Flood Fill 洪水灌溉模型>
    题目:题解:#include<stdio.h>intn,m;chararr[110][110];//元数据数组intcount=0;//计数器intdx[8]={1,1,1,-1,-1,-1,0,0};intdy[8]={-1,0,1,-1,0,1,1,-1};intt[110][110];//判断是否被选择voiddfs(intx,inty){for(inti=0;i<......
  • (算法) 入门——<迷宫问题>
    题目:题解:#include<stdio.h>intw,h;chararr[20][20];//初始值数组intt[20][20];//判断是否被选择的数组intdx[4]={0,0,-1,1};intdy[4]={1,-1,0,0};intcount=1;//计数器voiddfs(intx,inty){for(inti=0;i<4;i++)//暴力穷......
  • Leetcode1681-模拟,位运算
    题目链接:https://leetcode.cn/problems/count-the-number-of-consistent-strings/description/32位int构造出现过的字符集合位运算解法:用按位或(|)构造1个32位的数字集合A存用过的字符,此时对目标串构造字符集合B(有B是A子集,A∪B=A),注意运算优先级 题目:给你一个由不同字符......
  • 代码随想录算法训练营第8天 | 字符串
    344反转字符串voidreverseString(vector<char>&s){chartmp; inti=0,j=s.size()-1; while(i<j) { tmp=s[i]; s[i]=s[j]; s[j]=tmp; i++;j--; }}swap库函数的实现:位运算法——按位异或s[i]^=s[j];s[j]^=s[i];s[i]^=s[j];54......
  • 【图论】3.30学习记录 k短路(A*算法)
    从最短路说起的k短路3.26看了最短路和次短路。我们发现次短路实际上就是把最短路给破坏掉然后跑最短路...那我想...是不是破坏(k-1)次就能得到k短路呢,很显然是的,但是复杂度比较高,(因为一次dij是O(nlogn)级别的,次短路的话最坏要跑m次当最短路有m条边的时候)那么k比较大的时候就......
  • Java 递归算法系列:建议收藏的 13 个经典问题的代码实现详解
    递归算法题求阶乘(Factorial)斐波那契数列(FibonacciSequence)汉诺塔(TowerofHanoi)遍历树节点(TreeTraversal)数组反转(ArrayReversal)爬楼梯问题(ClimbingStairsProblem)回文数检测(PalindromeChecking)找出数组中的最大值(FindingMaximumValueinanArray)分治算法......
  • Leetcode算法训练日记 | day11
    一、有效的括号1.题目Leetcode:第20题给定一个只包括'(',')','{','}','[',']'的字符串s,判断字符串是否有效。有效字符串需满足:1.左括号必须用相同类型的右括号闭合。2.左括号必须以正确的顺序闭合。3.每个右括号都有一个对应的相同类型的左括号。示例1:输入:s="()"......
  • Leetcode算法训练日记 | day10
    一、用栈实现队列1.题目Leetcode:第232题请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):实现MyQueue类:voidpush(intx)将元素x推到队列的末尾intpop()从队列的开头移除并返回元素intpeek()返回队列开头的元素......
  • KMP算法
    一.概述要解决的问题:字符串匹配问题。目标串target:"aabaabaafa"模式串pattern:"aabaaf"传统算法:双层for循环遍历目标串target和模式串pattern,判断pattern在target第一次出现的位置。时间复杂度为:\(O(pattern.size()*target.size())\)=\(O(m*n)\)KMP算法核心思路:在对目标......