LeetCode《初级算法》字符串之实现strStr() -- JavaScript

359 阅读1分钟

题目

题目链接:leetcode-cn.com/leetbook/re…

image.png


题解


题目是字符串匹配,数据结构的经典题型,一般教材上都会提供两种算法,BF 解法 和 KMP 解法;

1、暴力(BF)解法

/**
 * @param {string} haystack
 * @param {string} needle
 * @return {number}
 */
var strStr = function(haystack, needle) {

    
    const hLen = haystack.length,
        nLen = needle.length;

    if(nLen === 0) {
        return 0;
    }
    if(nLen <= hLen) {
        
        let i = j = 0;
        while(i < nLen && j < hLen) {
            
            if(haystack[j] === needle[i]) {
                i++;
                j++;
            }else {
                j = j - i + 1;
                i = 0;
                
            }
            
        }
        if(i === nLen) {
            return j - i;
        }
    }
    return -1;
};

2、KMP 解法

kmp 的原理是利用子串的特性(前缀和后缀有多少相等,算法中表现为 next 数组),使指向主串的指针不用回溯, kmp 的重点:

  • 理解子串的 next 数组的含义和求 next 数组;
  • 匹配时指向子串的下标应该怎样利用 next 数组变换;
/**
 * @param {string} haystack
 * @param {string} needle
 * @return {number}
 */
var strStr = function(haystack, needle) {

    let hLen = haystack.length;
    let nLen = needle.length;
    if(nLen > hLen) {
        return -1;
    }
    if(nLen === 0) {
        return 0;
    }
    let next = new Array(nLen).fill(0); // 使用fill构造一个数组
    

    // 求 next 数组
    for(let i = 1;i < nLen;i++) {
        
        
        for(let m = 1;m <= i;m++){
            let n = 0;
            let nex = 0;
            while((m + n)<=i && needle[n] === needle[m+n]) { // 使用 m+n , 而改变 m
                n++;
                nex++;
            }
            if((m + n) > i) {
                next[i] = nex;
                break; // 记住要break
            }
        }

    }




    // 匹配字符串
    let j = 0;
 
    for(let i = 0;i < hLen;i++) { // 这里是小于 hLen,因为完全有可能出现 hLen-nLen < i < hLen 的一轮循环

        let flag = 0;
        while(j < nLen) {
            if(haystack[i] === needle[j]) {
                i++;
                j++;
                flag = 1;
            }else {
                break;
            }
        }


        if(nLen === j) {
            return i - j;
        }else if(0 === j) { // 处理 j === 0 时,访问 next[j] 越界问题;
            continue;
        }else {

            j = next[j-1]; // 匹配的重点,借助 next 数组改变子串的下标 j,而不用回溯主串下标 i

            i--; // 重点,如果到了这里一定是要把 i 减 1,以保持下一轮还是和这个为匹配的 haystack[i] 比较

            
        }
    }
    return -1;

};

3、直接用 JS 提供的 API

这是一个非常快捷,并且会使程序时空复杂度非常低的方法;

因为那些 JS 引擎都是大神搞出来的,他们一般都是以最优的算法去实现 JS 的 api;

但是如果是学习算法和练习算法的话并不推荐这样做,因为这样并不能使我们的算法能力得到提高;

var strStr = function(haystack, needle) {

    return haystack.indexOf(needle);

};

大家如果有更好的思路和解法,欢迎大家一起来讨论啊~


这是使用 JavaScript 对 LeetCode《初级算法》的每道题的总结和实现的其中一篇,汇总篇在这里:

juejin.cn/post/700669…