916.单词子集--力扣

8 篇文章 0 订阅
4 篇文章 0 订阅

题目描述

给你两个字符串数组 words1 和 words2。

现在,如果 b 中的每个字母都出现在 a 中,包括重复出现的字母,那么称字符串 b 是字符串 a 的 子集 。

例如,“wrr” 是 “warrior” 的子集,但不是 “world” 的子集。
如果对 words2 中的每一个单词 b,b 都是 a 的子集,那么我们称 words1 中的单词 a 是 通用单词 。

以数组形式返回 words1 中所有的通用单词。你可以按 任意顺序 返回答案。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/word-subsets
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

  • 示例一
输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]
输出:["facebook","google","leetcode"]
  • 示例二
输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","o"]
输出:["facebook","google","leetcode"]
  • 示例三
输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["e","oo"]
输出:["facebook","google"]
  • 示例四
输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["lo","eo"]
输出:["google","leetcode"]
  • 示例五
输入:words1 = ["amazon","apple","facebook","google","leetcode"], words2 = ["ec","oc","ceo"]
输出:["facebook","leetcode"]

题目分析

初级分析(错误答案)

  1. 首先 看第一第二个例子,我们不难看出,就是在words1中找到是否同时存在words2中的单词,一开始我的想法是用到了正则表达式,将words2中的每一个字母遍历然后用正则返回真假
/**
 * @param {string[]} words1
 * @param {string[]} words2
 * @return {string[]}
 */
var wordSubsets = function(words1, words2) {
    let res = []
            words1.forEach(element => {
                let flag = true
                words2.forEach(value => {
                    let i = value.length - 1
                    while (i >= 0) {
                        let reg = RegExp(value[i])
                        i--
                        if (!reg.test(element)) flag = false
                    }
                })
                if (flag) res.push(element)
            });
            return res
};
  1. 首先 第一个foreach是用来遍历待判断单词的数组
  2. 第二个foreach是用来遍历要存在内容的数组
  3. 而最里面的循环则是将存在内容分割成一个个的单词,然后通过正则进行判断 通过改变flag真假 决定是否放进新的res数组中去
    由结果可知,这种思路是错误的
  4. 提交结果
    在这里插入图片描述

可以看到,当words2中存在字母相同时,也就是字母个数重复的时候,测试用例不再通过

而我们的测试结果是
在这里插入图片描述

题解(正确答案)

思路:

首先,我们要记录在words2中,单词出现重复的个数
看到案例4 和 案例5 ,发现其实我们无需理会word2每个数组中单词里面字母的顺序,只要存在即可

那我们是不是可以只记录每个单词存在的最大个数,看words1中的哪些单词是否满足然后将其提取出来呢

我们可以想到,先创建26个大小空的元素的数组B,里面记录的是在word2中,每个字母出现的最大次数

//创建一个26大小的全0的数组
let B=new Array(26).fill(0) 
	//foreach对word2进行遍历 
	//value指的是每一次遍历word2对应的内容
    words2.forEach(value=>{ 
    	//创建一个临时的空的数组--用来防止重复的字母个数添加
        let tmp=new Array(26).fill(0) 
        //对value中的每一个字母进行遍历 
        //w指的是每一次遍历中value对应的单词
        for(let w of value){ 
        	//idx是用来记录这个字母对应的下标 
            //比如a的asc2码值就是97 那97-97=0 
            //所以在数组中表示a出现的次数的位置就是B[0]
            let idx=w.charCodeAt()-97 
            //判断对应位置中,B和tmp对应位置的单词个数是否相同
            if(tmp[idx]===B[idx]){
                B[idx]++
            }
            //(下面解释)
            tmp[idx]++
        }
    })

有效的防止了重复添加单词个数的问题

对于tmp功能的解释:
当第一次循环遍历的时候,tmp和B都是空数组,所以B都是正常增加,而第二次循环的时候,B中已经有了第一次循环的数,而tmp则是重新创建,任然是一个空的数组,那么功能到底是什么呢?

举个例子,第一次遍历到是aa,那B[0]=2,
第二次遍历到是aaa,b[0]=2,tmp[0]=0
第一次循环:得到:b[0]=2,tmp[0]=1
判断tmp[idx]===B[idx]不相等,所以B不加一,而tmp加一
第二次循环:得到:b[0]=2,tmp[0]=2
判断tmp[idx]===B[idx]不相等,所以B不加一,而tmp加一
第二次循环:得到:b[0]=3,tmp[0]=3
判断tmp[idx]===B[idx]相等,所以B加一,tmp加一

然后我们再遍历word1中每个单词,每个单词又遍历每个字母,如果该字母的对应位置是数组B中有记录的,则对应下标位置数量减一,如果说,循环结束,得到一个全0的数组,那么就可以说明该单词符合条件

return words1.filter(value=>{
        let tmp=B.slice()
        //slice() 方法,能够基于当前数组中的一或多个项创建一个新数组。
        for(let w of value){
            let idx=w.charCodeAt()-97
            if(tmp[idx]>0){
                tmp[idx]--
            }
        }
        return tmp.every(net=>net===0)
    })

every()–用于检测数组所有元素是否都符合指定条件(通过函数提供)。测试一个数组内的所有元素是否都能通过某个指定函数的测试。它返回一个布尔值。
filter()-- 创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
slice()–,能够基于当前数组中的一或多个项创建一个新数组。

全部代码

/**
 * @param {string[]} words1
 * @param {string[]} words2
 * @return {string[]}
 */
var wordSubsets = function(words1, words2) {
    let B=new Array(26).fill(0)
    words2.forEach(value=>{
        let tmp=new Array(26).fill(0)
        for(let w of value){
            let idx=w.charCodeAt()-97
            if(tmp[idx]===B[idx]){
                B[idx]++
            }
            tmp[idx]++
        }
    })
    return words1.filter(value=>{
        let tmp=B.slice()
        for(let w of value){
            let idx=w.charCodeAt()-97
            if(tmp[idx]>0){
                tmp[idx]--
            }
        }
        return tmp.every(net=>net===0)
    })
};

测试结果

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值