单词子集--特征思想的运用

0x01.问题

我们给出两个单词数组 AB。每个单词都是一串小写字母。
现在,如果 b 中的每个字母都出现在 a 中,包括重复出现的字母,那么称单词 b 是单词 a 的子集。 例如,“wrr” 是 “warrior” 的子集,但不是 “world” 的子集。
如果对 B 中的每一个单词 bb 都是 a 的子集,那么我们称 A 中的单词 a 是通用的。
你可以按任意顺序以列表形式返回 A 中所有的通用单词。
输入示例:A = [“amazon”,“apple”,“facebook”,“google”,“leetcode”], B = [“ec”,“oc”,“ceo”]
输出示例:[“facebook”,“leetcode”]
提示:
A[i]B[i] 只由小写字母组成。
A[i] 中所有的单词都是独一无二的,也就是说不存在 i != j 使得 A[i] == A[j]

 1 <= A.length, B.length <= 10000
C++ 函数形式为:vector<string> wordSubsets(vector<string>& A, vector<string>& B)

此题来源于leetcode

0x02.分析问题

查找单词问题,首选仿造的哈希表,只需要对A的每个单词,在B中遍历所有的单词,看是否满足就行了。

0x03.最初代码

class Solution {
public:
    vector<string> wordSubsets(vector<string>& A, vector<string>& B) {
        vector<string> result;
        int i,j,k,h;
        for(i=0;i<A.size();i++){
            vector<int>table(26,0);
            for(j=0;j<A[i].size();j++){
                table[A[i][j]-'a']++;
            }
            for(k=0;k<B.size();k++){
                vector<int>Table(table);
                for(h=0;h<B[k].size();h++){
                    if(Table[B[k][h]-'a']>=1){
                        Table[B[k][h]-'a']--;
                    }
                    else break;
                }
                if(h==B[k].size()) continue;
                else break;
            }
            if(k==B.size()) result.push_back(A[i]);
            else continue;
        }
        return result;
    }
};

这段代码并没有错误,但是实在是太暴力了,因为已经达到O(N^3)了,当然没有通过。

于是思考怎么优化。。。。。。

首先想得是怎么把这个三层循环变成二层循环,二层肯定是必须得,因为必须遍历到A中得所有单词嘛,所有目光就投向了B数组。

题目的意思是如果B中每个单词都是A中一个单词的子集的话,那么A中的那个单词就算是一个通用单词,所有我们可以找办法一次性,将B中的单词合起来,何A中的一个单词比较。

因为上面暴力比较的核心就是每个单词出现的次数,所以我们组合起来的那个B单词,应该包含每个小单词中字符出现次数最高的那个字符。

这个在B中小单词中出现次数最高的字符就是特征字符,因为只要单词中这个字符的数量都匹配了,那么其余小单词肯定是匹配的。

这种思想,叫做特征思想

这样我们就可以把一个内存的循环转变为外层的循环,而且因为每个单词的字符都小于10,所以可以忽略不计,时间复杂度接近 O(N)

0x04.最终解决代码

class Solution {
public:
    vector<string> wordSubsets(vector<string>& A, vector<string>& B) {
        vector<string> result;
        int i, j, k, h, m;
        vector<int> tableb(26, 0);
        for (k = 0; k < B.size(); k++) {
            vector<int> tablebtemp(26, 0);
            for (h = 0; h < B[k].size(); h++) {
                tablebtemp[B[k][h] - 'a']++;
            }
            for (m = 0; m < 26; m++) {
                tableb[m] = max(tableb[m], tablebtemp[m]);
            }
        }
        for (i = 0; i < A.size(); i++) {
            vector<int>tablea(26, 0);
            for (j = 0; j < A[i].size(); j++) {
                tablea[A[i][j] - 'a']++;
            }
            for (m = 0; m < 26; m++) {
                if (tablea[m] >= tableb[m]) continue;
                else break;
            }
            if (m == 26) result.push_back(A[i]);
        }
        return result;
    }
};

ATFWUS  --Writing  By 2020–03–18

  • 22
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ATFWUS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值