剑指offer|| 005.单词长度的最大乘积

面试题5:单词长度的最大乘积

力扣链接:https://leetcode-cn.com/problems/aseY1I/

题目描述

给定一个字符串数组words,请计算当两个字符串words[i]和words[j]不包含相同字符时,它们的长度的乘积的最大值。假设字符串只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回0。

样例输入1

words = [“abcw”,“baz”,foo",“bar”,“fxyz”,“abcdef”]

样例输出1

16
解释:“abcw"和"fxyz”

样例输入2

words = [“a”,“ab”,“abc”,“d”,“cd”,“bcd”,“abcd”]

样例输出2

4
解释:“ab"和"cd”

样例输入3

words = [“a”,“aa”,“aaa”,“aaaa”]

样例输出3

0


解析

解决这个问题的关键在于如何判断两个字符串str1和str2中没有相同的字符。一个直观的想法就是基于字符串str1中的每个字符ch,扫描字符串str2判断字符ch是否出现在str2中。如果两个字符串的长度分别为p和q,那么这种蛮力法的时间复杂度为O(pq)。显然是不可取的,我们可以用哈希表进行优化。

哈希表记录字符串中出现的字符

对于每个字符串,可以用一个哈希表记录出现在该字符串中的所有字符。在判断两个字符串str1和str2中是否有相同的字符时,只需要从’a’到’z’判断某个字符串是否在两个字符串对应的哈希表中都出现了。利用哈希表查找的速度是O(1)。这个题目假设所有字符都是英文小写字母,只有26个可能的字符,因此最多只需要在每个字符串对应的哈希表中查询26次就能判断两个字符串是否包含相同的字符。时间复杂度是O(1)。

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int n=words.size();
        vector<vector<bool>> vis(n,vector<bool>(26,false));
        //预处理
        for(int i=0;i<n;i++){
            int m=words[i].size();
            for(int j=0;j<m;j++) vis[i][words[i][j]-'a']=true;
        }
        int ans=0;
        //开始循环
        for(int i=0;i<n;i++){
            int a=words[i].size();
            for(int j=i+1;j<n;j++){
                int b=words[j].size();
                int flag=0;
                for(int k=0;k<26;k++){
                    if(vis[i][k]&&vis[j][k]) {flag=1;break;}
                }
                if(flag==0) ans=max(ans,a*b);
            }
        }
        return ans;
    }
};

上述代码分为两部分。第一步,初始化每个字符串对应的哈希表。时间复杂度是O(nk)其中n表示字符串的规模,k表示每个字符串长度的规模。第二步,根据哈希表找到不含相同字符的两个字符串的最大乘积,时间复杂度是O(n2)。总的时间复杂度就是O(nk+n2)。

用整数的二进制数位记录字符串中出现的字符

继续优化:既然每个字符串中的字符都是小写字符,不重复的字符最多有26个,而一个整数能够存储32个比特位,于是乎可以使用二进制记录字符串中出现的每个字符。出现的字符i就在二进制从右往左数第(i-‘a’)个数位上显示1否则显示0。如果两个字符串中不包含相同的字符,那么这两个字符串按位与&的结果一定是0,可以根据这个判断两个字符串是否含有相同的字符。

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int n=words.size();
        vector<int> flag(n,0);
        for(int i=0;i<n;i++){
            for(char c:words[i]) flag[i] |= 1<<(c-'a');
        }
        int ans=0;
        for(int i=0;i<n;i++){
            for(int j=i+1;j<n;j++){
                if((flag[i]&flag[j])==0) {
                    int te=words[i].size()*words[j].size();
                    ans=max(ans,te);
                }
            }
        }
        return ans;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值