leetcode刷题:字符串06(实现 strStr())

93 篇文章 0 订阅

28. 实现 strStr()

力扣题目链接

实现 strStr() 函数。

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

示例 1:
输入: haystack = “hello”, needle = “ll”
输出: 2

示例 2:
输入: haystack = “aaaaa”, needle = “bba”
输出: -1

说明:
当 needle 是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。
对于本题而言,当 needle 是空字符串时我们应当返回 0 。这与C语言的 strstr() 以及 Java的 indexOf() 定义相符。

本来想要字符串模式匹配算法KMP算法的,结果我没写出来,害。

package com.programmercarl.string;

/**
 * @ClassName StrStr
 * @Descriotion TODO
 * @Author nitaotao
 * @Date 2022/6/25 15:52
 * @Version 1.0
 * https://leetcode.cn/problems/implement-strstr/
 * 实现 strStr()
 **/
public class StrStr {
    public static void main(String[] args) {
        System.out.println(strStr("bababbababbbabbaa", "" +
                "abbba"));
    }

    /**
     * 串的模式匹配算法
     * 除了特殊情况
     * 1. 遍历大串
     * 2. 遍历小串
     * 当小串的当前字符和大串的一样时,比较下一位,如果一直到最后都相等,返回
     * 如果中间遇到不相等的,则大串后移n位
     * n为小串中下一个和首字母相同的位
     *
     * @param haystack
     * @param needle
     * @return
     */
    public static int strStr(String haystack, String needle) {
        //判断特殊情况
        if ("".equals(needle)) {
            return 0;
        }

        if (haystack.length() < needle.length()) {
            return -1;
        }

        int bigIndex = 0;

        //串内偏移量
        int offset = 0;
        while (bigIndex < haystack.length()) {
            while (needle.charAt(offset) == haystack.charAt(bigIndex + offset)) {
                //双方后移继续比较
                if (offset == needle.length() - 1) {
                    return bigIndex;
                } else {
                    offset++;
                }
                //大串结束
                if (bigIndex + offset > haystack.length() - 1) {
                    break;
                }
            }
            bigIndex++;
            offset = 0;
        }
        return -1;
    }
}

在这里插入图片描述

看看KMP算法的解法。有一说一,手算咱都会,一到代码就看不懂了。
已经在这卡了一两天了。似懂非懂。https://www.bilibili.com/video/BV16X4y137qw 讲的还算清楚,但是我还是迷迷糊糊的。
整体思路就是先算出next数组。这个数组是干嘛用的呢,先来了解一些定义:
1.前缀:包含首位字符但不包含末位字符的子串。
2.后缀:包含末位字符但不包含首位字符的子串。
3.next数组定义:当主串与模式串的某一位不匹配时,模式串要回退的位置。
4.next[ j ]:其值=第 j 位字符前面 j - 1 位字符组成的子串的前后缀重合字符数 + 1。


    public int strStr(String haystack, String needle) {
 	    if (needle.length() == 0) {
            return 0;
        }

        int[] next = new int[needle.length()];
        //获取模式串的前缀表
        getNext(next, needle);

        int j = 0;
        //i 为父串当前被匹配的字符的位置
        for (int i = 0; i < haystack.length(); i++) {
            // j 在子串中遍历      i 在父串中遍历
            while (j > 0 && needle.charAt(j) != haystack.charAt(i)) {
                // 如果 父串的 I 位置 与 子串的 J 位置发生不匹配,
                // 子串 就跳到 与这个后缀相等的 前缀 的后面 继续匹配
                // 就是 前一个匹配后缀的前缀的后面
                j = next[j - 1];
            }
            //如果当前字符匹配成功,继续匹配下一位,i++在for循环中
            if (needle.charAt(j) == haystack.charAt(i)) {
                j++;
            }
            //如果子串已匹配长度和子串长度相等,返回结果
            if (j == needle.length()) {
                return i - needle.length() + 1;
            }
        }

        //没有找到
        return -1;

    }

    public static void getNext(int[] next, String s) {
        int j = 0;
        //第0位不计入,因为第0位没有前缀
        next[0] = 0;
        //从第一位开始算
        for (int i = 1; i < s.length(); i++) {
            // 当 j == 0 时,直接跳出while循环了
            while (j > 0 && s.charAt(j) != s.charAt(i)) {
                j = next[j - 1];
            }
            if (s.charAt(j) == s.charAt(i)) {
                j++;
                // i++在循环里
            }
            next[i] = j;
        }

    }

在这里插入图片描述

过了半天,不好意思兄弟们。我看懂了。我们不一样了。

    public static void getNext(int[] next, String s) {
        // j 是后缀的最后一位,也是 i包括 i 之前最长子串前后缀相等的长度
        int j = 0;
        //第0位不计入,因为第0位没有前缀
        next[0] = 0;
        // i 是前缀的最后一位
        // 从第一位开始算
        for (int i = 1; i < s.length(); i++) {
            //遍历i的每一位
            // 当 前后缀 不相等 并且 j > 0 防止越界
            while (j > 0 && s.charAt(i) != s.charAt(j)) {
                //查找前缀表的前一位,就是上一个j的值,让上一个j的位置的元素和当前i进行比较
                // j-1是前一位
                //因为相等时 最大相同前后缀 是一个个加上来的,比较时也要一个个回退回去比较
                j = next[j - 1];
            }
            //如果相等
            if (s.charAt(i) == s.charAt(j)) {
                // j 是后缀表的最后一位
                // 同时!也是 包括 I 的最长子串前后缀相等的长度
                // 相等位数 j+1
                j++;
                //此时 i 也需要后移,继续比较下一位
                // 在 for 循环中会自动 i + 1
            }
            //更新当前 i 位置 的 next 数组的值
            next[i] = j;
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值