leetcode 438 找到字符串中所有字母异位词(滑动窗口+桶)

题目:

给定两个字符串 s 和 p,找到 s 中所有 p 的异位词的子串,返回这些子串的起始索引。不考虑答案输出的顺序。

异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。

示例 1:
输入: s = “cbaebabacd”, p = “abc”
输出: [0,6]
解释:
起始索引等于 0 的子串是 “cba”, 它是 “abc” 的异位词。
起始索引等于 6 的子串是 “bac”, 它是 “abc” 的异位词。
示例 2:
输入: s = “abab”, p = “ab”
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 “ab”, 它是 “ab” 的异位词。
起始索引等于 1 的子串是 “ba”, 它是 “ab” 的异位词。
起始索引等于 2 的子串是 “ab”, 它是 “ab” 的异位词。

提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母

思路分析:

1.全排列(失败,堆栈溢出)

可以看出s,p的长度都比较大,本来写了一个把p全排列再在s中找子串的算法:

(1)include

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function (s, p) {
    let len1 = s.length
    let len2 = p.length
    if(len2>len1){
        return []
    }
    let diff = len1 - len2
    let fullPermulateArr = []
    let newStr = ""
    let numArr = []
    fullPermulateArr = fullpermutate(p)
    
    for (let i = 0; i < diff + 1; i++) {
        newStr = s.slice(i, i + p.length)
        if (fullPermulateArr.includes(newStr)) {
            numArr.push(i)
        }
    }
    return numArr
};
function fullpermutate(str) {
    var result = [];
    if (str.length > 1) {
        //遍历每一项
        for (var m = 0; m < str.length; m++) {
            //拿到当前的元素
            var left = str[m];
            //除当前元素的其他元素组合
            var rest = str.slice(0, m) + str.slice(m + 1, str.length);
            //上一次递归返回的全排列
            var preResult = fullpermutate(rest);
            //组合在一起
            for (var i = 0; i < preResult.length; i++) {
                var tmp = left + preResult[i]
                result.push(tmp);
            }
        }
    } else if (str.length == 1) {
        result.push(str);
    }
    return result;
}

(2)indexOf

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function (s, p) {
    let len1 = s.length
    let len2 = p.length
    if (len2 > len1) {
        return []
    }
    let set=new Set()
    let diff = len1 - len2
    let fullPermulateArr = []

    let permulateStr = ""
    let index = null
    let newIndex = 0
    let numArr = []
    fullPermulateArr = fullpermutate(p)
    for (let j = 0, len = fullPermulateArr.length; j < len; j++) {
        permulateStr = fullPermulateArr[j]
        newIndex=0
        while (s.indexOf(permulateStr, newIndex) !== -1 && newIndex < len1) {
            index = s.indexOf(permulateStr, newIndex)
            numArr.push(index)
            newIndex = index + 1
           
        }
    }
   
   set.add(numArr)
    return set
};
//求q的全排列
function fullpermutate(str) {
    var result = [];
    if (str.length > 1) {
        //遍历每一项
        for (var m = 0; m < str.length; m++) {
            //拿到当前的元素
            var left = str[m];
            //除当前元素的其他元素组合
            var rest = str.slice(0, m) + str.slice(m + 1, str.length);
            //上一次递归返回的全排列
            var preResult = fullpermutate(rest);
            //组合在一起
            for (var i = 0; i < preResult.length; i++) {
                var tmp = left + preResult[i]
                result.push(tmp);
            }
        }
    } else if (str.length == 1) {
        result.push(str);
    }
    return result;
}



在p.length=23的时候,n^2的时间复杂度终于顶不住了,这个思路以堆栈溢出而宣告失败…

2.词频统计(桶)

可以new一个大小为26的arr,来统计p所有字母出现的次数.再用滑动窗口对s进行一一匹配(窗口大小固定,为p的长度),每移动一次只需要让s桶的第一个字符的频次-1,指针后移,新添加的元素频次+1,这样不用算全排列;只需要看两个相同大小的桶是否相等就ok了.

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function (s, p) {
    let len1 = s.length
    let len2 = p.length
    if(len2>len1){
        return []
    }
    let numArr = []
    //使用桶
    let Ascii_a = "a".charCodeAt()
    let bucket_s = new Array(26).fill(0)
    let bucket_p = new Array(26).fill(0)
    for (let j = 0; j < len2; j++) {
        bucket_p[p[j].charCodeAt() - Ascii_a]++
        bucket_s[s[j].charCodeAt() - Ascii_a]++
    }
    if (bucket_s.toString() === bucket_p.toString()) {
        numArr.push(0)
    }
    for (let i = 0; i < len1 - len2; i++) {
        bucket_s[s[i].charCodeAt() - Ascii_a]--
        bucket_s[s[i + len2].charCodeAt() - Ascii_a]++
        if (bucket_s.toString() === bucket_p.toString()) {
            numArr.push(i + 1)
        }
    }
    return numArr
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值