代码随想录算法训练营day9|28. 找出字符串中第一个匹配项的下标,459.重复的子字符串,字符串总结,双指针回顾

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

力扣

思路:KMP

【kmp算法】最长相等前后缀,用next[]数组储存。

1. j 指向前缀末尾位,也代表包括 i 之前的子串的最长相等前后缀的长度。i 指向后缀末尾位。

2. 初始化:j = 0; next[0] = 0; i =1 ;

3. 循环不变量:遇见冲突看前一位。当前后缀不相等时,j 回退到下标为它的前一位的值的位置。当前后缀相等时,j后移,更新next数组的值。

注意:needle字符串作为模式串,因此是要获得needle字符串的next数组;

class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length()==0) return 0;
        if(needle.length()>haystack.length()) return -1;
        int[] next = getNext(needle);//获得模式串的前缀表
        for(int i=0,j=0;i<haystack.length();i++){
            while(j>0 && needle.charAt(j)!=haystack.charAt(i)){
                j=next[j-1];//j回退
            }
            if(needle.charAt(j)==haystack.charAt(i)){
                if(j==needle.length()-1){//匹配结束,返回i-j
                    return i-j;
                }
                j++;
            }
        }
        return -1;
    }
    public int[] getNext(String s){
        int[] next = new int[s.length()];
        for(int i=1,j=0;i<s.length();i++){
            while(j>0 && s.charAt(i)!=s.charAt(j)){//字符不匹配
                j=next[j-1];
            }
            if(s.charAt(i)==s.charAt(j)){//字符相匹配
                j++;
            }
            next[i]=j;//更新next[]
        }
        return next;
    }
}

思路:基于滑动窗口的算法

1. 利用两个指针,找到文本串中第一个相匹配的字符后,依次匹配;

2. 每次遇到字符不相同的情况,文本串的查找起始位置向右移动一位,模式串从头开始;

class Solution {
    public int strStr(String haystack, String needle) {
        int n=needle.length(),h=haystack.length();
        if(n==0) return 0;
        if(n>h) return -1;
        int i=0,j=0;
        while(i<h-n+1){//haystack中第一个匹配的字符下标一定<h-n+1
            while(i<h && haystack.charAt(i)!=needle.charAt(j)){
                i++;
                if(i==h-n+1) return -1;
            }
            while(i<h && j<n && haystack.charAt(i)==needle.charAt(j)){
                i++;
                j++;
            }
            if(j==n) return i-j;
            i-=j-1;//-1:i需要回退后向右移动一步
            j=0;
        }
        return -1;
    }
}

459.重复的子字符串

力扣

思路:

【kmp算法】

1. 在由重复子串组成的字符串中,最长相等前后缀不包含的子串就是最小重复子串。如图,s[0]s[1] = t[0]t[1] = k[0]k[1] = t[2]t[3] = s[2]s[3];s[0]s[1] 一定是最小重复子串。

「数组长度」-「最长相同前后缀的长度」=「一个周期的长度」

2.假设字符串s由多个重复子串(最小重复单位,长度x)构成,则s.length()=n*x;由于s的最长相同前后缀一定不包含s本身,所以最长相同前后缀长度必然是m*x,且 n-m=1。

3. 那么如果len % (len - (next[len - 1] + 1)) == 0 ,就说明该字符串有重复子字符串。「一个周期的长度」可以被「字符串长度」整除,则说明字符串由重复子串组成。

【注意】next[len-1] 若为0,则说明没有相同前后缀,返回false;

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        int[] next = getNext(s);//得到next[]
        int len = s.length();
        int sub = len-next[len-1];//[一个周期的长度]
        if(next[len-1]>0 && len%sub==0) return true;
        return false;
    }
    public int[] getNext(String s){
        int[] next = new int[s.length()];
        for(int i=1,j=0;i<s.length();i++){
            while(j>0 && s.charAt(i)!=s.charAt(j)){
                j=next[j-1];
            }
            if(s.charAt(i)==s.charAt(j)){
                j++;
            }
            next[i]=j;
        }
        return next;
    }
}

字符串总结

1. 双指针法

        在数组,链表和字符串中很常用。

2. 数组填充类问题

        可以预先把数组扩容至填充后的大小,然后从后往前操作。

3. 固定规律一段段处理字符串

        在for循环的表达式上做文章,使程序更高效。

4. KMP算法

        主要思想:​​​​​​​利用前缀表记录已匹配的文本内容,当字符串不匹配时,避免从头匹配。

        用于两类经典问题:(1)匹配;(2)重复子串;

        前缀:指不包含最后一个字符的所有以第一个字符开头的连续子串。

        后缀:指不包含第一个字符的所有以最后一个字符结尾的连续子串。

5. 反转的花样

        例如,先整体反转,再局部反转;先局部反转,再整体反转;

双指针回顾 

1. 数组篇

        原地移除数组中的元素:通过两个指针在一个for循环下完成两个for循环的工作。

2. 字符串篇

        原地反转字符串:双指针分别从字符串前面、后面同时向中间移动,并交换元素;

        原地填充字符串:先扩充数组替换后的大小,然后双指针从后向前进行替换;

3. 链表篇

        反转链表:改变链表的next指针指向,直接将链表反转 ;

        在链表中求环:定义 fast 和 slow 指针,从头结点出发,fast每次移动两节点,slow指针每次移动一节点,如果 fast 和 slow指针在途中相遇 ,则说明链表有环;分别从头结点和相遇节点出发一个指针,每次走一个节点, 这两个指针的相遇处就是环的入口;

4. N数之和篇

        三数之和:通过前后两个指针不断向中间逼近,在一个for循环下完成两个for循环的工作。将暴力O(n^3)解法,降为O(n^2)的解法;四数之和的双指针解法:将暴力O(n^4)的解法,降为O(n^3)的解法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的数组"。 首先是Leetcode 28题,题目要求在给定的字符串找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组找到长度最小的数组,
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值