【LeetCode 每日一题】982. 按位与为零的三元组(hard)

982. 按位与为零的三元组

牢记,当暴力铁超时的时候,尝试找规律或者记录中间结果


  首先,数据量是 1 < = n u m s . l e n g t h < = 1000 1 <= nums.length <= 1000 1<=nums.length<=1000,如果三重循环枚举,铁定超时,那怎么办呢,尝试找规律。(这题找不到规律,不想看分析就直接跳过)

  三个数字按位与的话,如果已经有两个数字按位与为0了,那第三个数字是什么都无所谓,这个组合可以与数组中的任何一个数字组成按位与为0的三元组。同时,第三个数字如果与这两个数字在数组中的下标互异,那这三个数字有三种组合方式;如果其中有两个数字下标相同,那么只有两种组合。可是问题来了,如果必须是三个数字都参与才能按位与为0呢,比如 1 、 2 、 4 1、2、4 124,这种情况还是只能通过枚举来找,所以找规律行不通,还是得暴力。

  然后我们注意到 0 < = n u m s [ i ] < 2 16 0<=nums[i] < 2^{16} 0<=nums[i]<216,很容易想到,任何一个 n u m s [ i ] & n u m s [ j ] nums[i]\&nums[j] nums[i]&nums[j]的结果依然在这个范围,因此,我们可以先两层循环,枚举两个数按位与能得到的所有结果的数量,用数组或者哈希表存一下,然后再一个两层循环,枚举哈希表里的数和原始数组里的数按位与,如果为0,则加上哈希表中的这个数的数量。最后的结果即是要求的组合数。

class Solution {
public:
    int countTriplets(vector<int>& nums) {
        map<int,int> cnt;
        int ans=0;
        for(auto i:nums){
            for(auto j:nums){
                cnt[i&j]++;
            }
        }
        for(auto k:nums){
            for(auto &v:cnt){
                if((k&v.first)==0){
                    ans+=v.second;
                }
            }
        }
        return ans;
    }
};

然后看了题解,发现还有优化空间。整体做法一致,优化在于遍历方式。具体看灵神题解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值