2022.03.07 KMP算法+ 力扣28,459,844,76

学习内容:kmp算法

follow:
代码随想录讲解kmp算法
图解+讲解kmp算法


28 实现strStr

题目描述:
实现 strStr() 函数。

给你两个字符串 haystack 和 needle ,请你在 haystack 字符串中找出 needle 字符串出现的第一个位置(下标从 0 开始)。如果不存在,则返回 -1 。

解析:
这道就是实现kmp算法

解答:

class Solution {
   public static int strStr(String haystack, String needle) {
        if(needle.length() == 0) return 0;
        //kmp算法
        //首先构造前缀表:每个数组下标表示,包含本字符的最长公共前后缀的长度
        int[] next = getNext(needle);
        //利用前缀表进行匹配
        int j = 0;
        for(int i = 0; i < haystack.length(); i++){
            while(j > 0 && haystack.charAt(i) != needle.charAt(j)){
                j = next[j - 1];
            }
            if(haystack.charAt(i) == needle.charAt(j)){
                j++;
            }
            if(j == needle.length()){
                return i - needle.length() + 1;
            }
        }
        return -1;
    }

    public static int[] getNext(String s){
        int[] next = new int[s.length()];
        char[] needle = s.toCharArray();
        //j代表了前缀末尾 + 1的位置,以及前缀的长度
        int j = 0;
        //初始化:next[0]的值为0,代表着第一个位置的公共前后缀的长度为0
        next[0] = j;
        //i代表了后缀末尾,以及遍历字符串的指针
        for(int i = 1; i < needle.length; i++){
            //如果目前正在匹配的后缀最后一位不相等
            //则退回到next[j]
            while(j > 0 && needle[i] != needle[j]){
                j = next[j - 1];
            }
            //如果匹配,则当前j为前缀末尾,j移到下一位
            if(needle[i] == needle[j]){
                j++;
            }
            next[i] = j;
        }
        return next;
    }
}
459. 重复的子字符串

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

解析:
使用kmp中的next数组

解答:

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        //构造next数组
        int[] next = getNext(s);
        int len = s.length();
        //len - (len - next[len - 1])可以被len整除,说明有重复的
        if(next[len - 1] > 0 && len % (len - next[len - 1]) == 0){
            return true;
        }
        return false;
    }

    public int[] getNext(String s){
        int length = s.length();
        int[] next = new int[length];
        //初始化
        int j = 0;
        next[0] = j;
        for(int i = 1; i < 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;
    }
}
844 比较含退格的字符串

题目描述:
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,如果两者相等,返回 true 。# 代表退格字符。

注意:如果对空文本输入退格字符,文本继续为空。

解析:
需要额外数组:从后向前遍历字符串,遇到#计数,遇到非#,根据计数进行回退

class Solution {
    public boolean backspaceCompare(String s, String t) {
       return backspace(s).equals(backspace(t));
    }

    public String backspace(String s){
        StringBuilder stringBuilder = new StringBuilder();
        int count = 0;
        for(int i = s.length() - 1; i >= 0; i--){
            if(s.charAt(i) == '#'){
                count++;
            }else{
                if(count > 0){
                    count--;
                }else{
                    stringBuilder.append(s.charAt(i));
                }
            }
        }
        return stringBuilder.toString();
    }
}
76 最小覆盖字串

题目描述:
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。

注意:

  • 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
  • 如果 s 中存在这样的子串,我们保证它是唯一的答案。

解析:
可以使用滑动窗口的方法

  • 当滑动窗口内不包含字符串t时,right指针向右移动
  • 当窗口内包含字符串t时,记录left、right,再向右移动left,直至不包含字符串t

自我认为的难点:如何判断窗口内包含字符串t——可使用一个计数count,当count==0时,滑动窗口包含所有字符串。

可以用数组保存字符串t出现的字符和次数,利用该数组决定count的值。

class Solution {
    public String minWindow(String s, String t) {
        if(s.length() == 0 || t.length() == 0 || s.length() < t.length()){
            return "";
        }
        //用数组来保存,因为都是英文字母,所以是有限的,可以使用数组来存储
        int[] record = new int[128];
        for(char i : t.toCharArray()){
            record[i]++;
        }
        //count用来衡量滑动窗口是否已经包含了t中所有字符
        int count = t.length();
        int left = 0, right = 0;
        int result = Integer.MAX_VALUE;
        int start = 0;
        for(; right < s.length(); right++){
            //说明目前滑动窗口没有包含所有t中字符
            if(record[s.charAt(right)] > 0){
                count--;
            }
            record[s.charAt(right)]--;

            
            //滑动窗口中包含了t中所有字符:count == 0,record对应字符的索引<=0
            while(left <= right && count == 0){
                if((right - left) < result){
                    result = right - left + 1;
                    start = left;
                }
                record[s.charAt(left)]++;
                //证明无法满足t中所有字符
                if(record[s.charAt(left)] > 0){
                    count++;
                }
                left++;
            }
        }

        if(result == Integer.MAX_VALUE){
            return "";
        }else{
            return s.substring(start, start + result);
        }
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值