【LeetCode】318. 最大单词长度乘积

318. 最大单词长度乘积(中等)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法一

思路

  • 这道题有两个要求:

    • length(words[i]) * length(words[j])最大值
    • 这两个单词不含有公共字母
  • 首先我们考虑第一个条件:长度乘积的最大值

    是否需要将 words 中的单词按照长度从大到小进行排序,然后逐一遍历?并不需要。比如,长度最长的单词为5,剩余的单词中不和它有公共字母的最长单词长度为2,它们的长度乘积为 10;然而长度第二的单词为 4 ,剩余的单词中不和它有公共字母的最长单词长度为3,它们的长度乘积为 12 。显然,需要遍历所有单词的可能结果才能得到最终答案,因此对长度排序是没有意义的,所以我们一开始不应该关注这个条件。

  • 那么我们考虑第二个条件:快速判断两个单词不包含相同字母

    由于这一章是围绕二进制展开的,因此我想到了 长度为 26 的哈希表,如果该字母出现过,就在其位置上标记为 1 。

    在判断两个单词是否包含相同字母的时候,我们可以对两个单词的哈希表逐一遍历,如果它们的哈希表同时出现 1 ,说明包含相同字母,此时将标志 flag 记为 false,并且退出这两个单词的判断。

  • 因此,总的算法思想就是:将所有单词两两遍历,判断它们是否包含公共字母,如果不包含的话,就计算它们的长度乘积,保留最大的长度乘积作为最终结果。

代码

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int ans = 0;
        int n = words.size();
        vector<vector<int>> letters(n, vector<int>(26, 0));
        // words预处理
        for(int i=0; i<n; ++i){
            for(char ch : words[i]){
                letters[i][ch - 'a'] = 1;
            }
        }
        // cout<<letters[0][0];

        for(int i=0; i<n; ++i){        
            for(int j=i+1; j<n; ++j){
                // flag = true:没有出现公共字母
                bool flag = true;
                for(int k=0; k<26; ++k){
                    // 如果两个单词包含公共字母,那么标记并遍历下一个单词
                    if(letters[i][k] == 1 && letters[j][k] == 1){
                        flag = false;
                        break;
                    }
                }
                // 如果不包含公共字母,那么计算它们的长度乘积
                if(flag){
                    int length = words[i].size() * words[j].size();
                    ans = max(ans, length);
                }
            }
        }
        return ans;
    }
};

方法二:优化

思路

  • 虽然我在方法一就用到了二进制的思想,但是它其实更符合哈希表,因为我并没有用到二进制的性质。

  • 那么如何巧妙利用二进制的性质呢?

    我们可以将两个单词的二进制表示按位与如果两个单词存在重复数字,那么它们按位与的结果不为 0

  • 因此,总的算法思想:为每个字母串建立长度为 26 的二进制数字,每个位置表示是否存在该字母。如果两个字母串不含有重复数字,那么它们的二进制表示的按位与为 0 ,此时计算它们的长度乘积并与最大值相比较,保留更大的那个值。

代码

class Solution {
public:
    int maxProduct(vector<string>& words) {
        int ans = 0;
        int n = words.size();
        vector<int> mask(n, 0);
        // words预处理
        for(int i=0; i<n; ++i){
            int temp = 0;
            for(char ch : words[i]){
                // 单词words[i]的二进制表示
                temp |= 1 << (ch -'a');
            }
            mask[i] = temp;
        }

        for(int i=0; i<n; ++i){        
            for(int j=i+1; j<n; ++j){
                // 没有出现公共字母
                if((mask[i] & mask[j]) == 0){
                    int length = words[i].size() * words[j].size();
                    ans = max(ans, length);
                }
            }
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值