欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

LeetCode 0028 -- 实现strStr()

程序员文章站 2024-03-17 17:53:10
...

实现strStr()

题目描述

示例 1:

输入: haystack = "hello", needle = "ll"
输出: 2

示例 2:

输入: haystack = "aaaaa", needle = "bba"
输出: -1

说明:

needle是空字符串时,我们应当返回什么值呢?这是一个在面试中很好的问题。

对于本题而言,当needle是空字符串时我们应当返回 0 。这与C语言的strstr()以及 Java的indexOf()定义相符。

解题思路

个人AC

声明两个游标hcnc

  • hchaystack cursor,用来辅助遍历字符串haystack
  • ncneedle cursor,用来辅助遍历字符串needle
class Solution {
    public int strStr(String haystack, String needle) {
        int hc = 0, nc = 0; // c即cursor,用来辅助遍历字符串
        int hLen = haystack.length(), nLen = needle.length();
        if (hLen < nLen) return -1;
        if (hLen == 0 && nLen == 0) return 0;
        
        while (hc < hLen) {
            int hRestC = hc;
            while (hRestC < hLen) {
                if (nc == nLen) return hc;
                
                char cOfH = haystack.charAt(hRestC), cOfN = needle.charAt(nc);
                if (cOfH == cOfN) {
                    hRestC++;
                    nc++;
                } else {
                    hc++;
                    nc = 0;
                    break;
                }
            }
        }
        return -1;
    }
}

时间复杂度: O(n2)O(n^2)

空间复杂度: O(1)O(1)

最优解

Sunday

Sunday匹配机制

  • 目标字符串:haystacktarget
  • 模式串:needlepattern
  • 当前查询索引:idx(初始为0);
  • 待匹配字符串:target.substring(idx, idx + pattern.length())

每次匹配都会从目标字符串中提取待匹配字符串模式串进行匹配:

  • 如果匹配,则返回idx

  • 若不匹配,则查看待匹配字符串的后一位字符c

    • c位于模式串中,则idx = idx + 偏移表[c]
    • 否则,idx = idx + pattern.length() + 1

    重复上述过程,直到idx + pattern.length() > target.length()

偏移表

偏移表的作用是存储每一个在模式串中出现的字符和其对应的偏移位(该字符在模式串中出现的最右位置到尾部的位置 + 1),如**模式串aab**的偏移表为:

  • a的偏移位为pattern.length() - i = 3 - 1 = 2
  • b的偏移位为pattern.length() - i = 3 - 2 = 1
  • 其它均为pattern.length() + 1 = 3 + 1 = 4

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7j22GM50-1573103113502)(assets/1573100111625.png)]

举例

target = checkthisoutpattern = this

S1:

LeetCode 0028 -- 实现strStr()

  • idx = 0待匹配字符串 = chec
  • 因为chec != this,所以查看chec下的后一个字符k是否在pattern中(查看偏移表),
  • k不在偏移表中,所以idx = idx + 1

S2:

LeetCode 0028 -- 实现strStr()

  • idx = 5待匹配字符串 = this
  • 因为this = this,所以返回idx = 5

实现

class Solution {
    public int strStr(String haystack, String needle) {
        int hLen = haystack.length(), nLen = needle.length();
        if (hLen < nLen) return -1;
        if (nLen == 0) return 0;
        
        // 计算偏移表
        HashMap<Character, Integer> shift = getShiftMap(needle);
        int hc = 0; // 即idx
        while (hc + nLen <= hLen) {
            // 待匹配字符串
            String subH = haystack.substring(hc, hc + nLen);
            // 判断是否匹配
            if (subH.equals(needle)) {
                return hc;
            } else {
                // 边界处理
                if (hc + nLen >= hLen) return -1;
                // 判断待匹配字符串的下一个字符是否在偏移表中
                char c = haystack.charAt(hc + nLen);
                if (shift.containsKey(c)) {
                    hc += shift.get(c);
                } else {
                    hc += nLen + 1;
                }
            }
        }
        return hc + nLen >= hLen ? -1 : hc;
    }
    
    private HashMap<Character, Integer> getShiftMap(String pattern) {
        HashMap<Character, Integer> shift = new HashMap<>();
        for (int i = 0; i < pattern.length(); i++) {
            char c = pattern.charAt(i);
            shift.put(c, pattern.length() - i);
        }
        return shift;
    }
}

时间复杂度: O(n)O(n),最坏情况为O(mn)O(m * n),其中n为目标串target的长度,m为模式串pattern的长度;

空间复杂度: O(n)O(n)

KMP