2023.3.4Leecode982按位与为零的三元组

Posted S1eepy^

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2023.3.4Leecode982按位与为零的三元组相关的知识,希望对你有一定的参考价值。

题目的要求

给你一个整数数组 nums ,返回其中 按位与三元组 的数目。

按位与三元组 是由下标 (i, j, k) 组成的三元组,并满足下述全部条件:

0 <= i < nums.length
0 <= j < nums.length
0 <= k < nums.length
nums[i] & nums[j] & nums[k] == 0 ,其中 & 表示按位与运算符。

 

题目的实例2

输入:nums = [0,0,0]
输出:27
  • 1 <= nums.length <= 1000
  • 0 <= nums[i] < 2^16


思路:
1.枚举
我们正常的解法可能就需要用三重的for循环,时间复杂度是O(n^3).在这里我们可以先用双重for循环来遍历 nums[i]&nums[j]的值,将他们存入到hash表中
这里我们直接采用数组作为hash表,nums[i]<2^16次方,nums[i]&nums[j] < 2^16。数组的长度最大开2^16次方.然后我们在进行双重for循环,第一层for
循环是接着遍历数组,第二重for循环我们就直接枚举m,判断 nums[k]&m是否等于0,等于0就去hash表中查找m是否存在(枚举值是否是之前进入hash表的nums[i]
&nums[j]),时间复杂度为O(n^2+n*2^16)
代码如下(typescript)
 function countTriplets(nums: number[]): number 
     //枚举法
     //用map(Array)来存放I下标和J下标的&值,然后再用双重for循环,一个是Z下标,一个值用来枚举map , 时间复杂度是O(n^2+2^16*n)
     const map = new Array(1 << 16).fill(0)
     //往map(数组)中添加元素
     for(const i of nums) 
         for(const j of nums)
             map[i&j]++
         
     
     let sum:number = 0
     //再用枚举获取数值
     for(const x of nums)
         for(let i:number = 0; i < (1<<16); i++) 
             if(<number>(x & i) == 0) 
                 sum += map[i]
             
         
     
     return sum
 ;

 

优化

在思路1的基础上我们可以采用子集优化的方式,在第二次遍历数组的时候我们获取到nums[k],假设将nums[k]转换成二维数组 5 = (101) ,将数值为1的下标放入到集合中,也就是1,3,命名为集合A。nums[k]&m等于0就代表nums[k]代表的集合和m代表的集合没有交集,m是CuA的子集。这样我们就可以直接枚举CuA的子集来优化算法。在本题中Cu是2^16也就是1,2,...,16也就是0xffff.有了Cu,那么我们如果遍历CuA的子集m呢。我们可以直接通过 m = (m-1)&CuA的写法来,一般来说是将m-1然后和CuA相与,如果结果是m-1代表它就是CuA的子集。(m-1)&CuA的写法的思路是,m-1的子集就是m的子集,m-1就是把m的最右位的1变成0,把该1右侧的0变成1,这样可以直接通过 & CuA快速获取到下一个子集.已经清楚了如何快速获取子集,那么结束的条件是啥呢, 当m-1达到-1时,-1的二进制码全是1,这个时候和CuA相与结果就变成了CuA,所以当m&CuA = CuA的时候就代表结束了这次操作

代码(typescript)

function countTriplets(nums: number[]): number 
    //枚举法
    const map = new Array(1 << 16).fill(0)
    //往map(数组)中添加元素
    for(const i of nums) 
        for(const j of nums)
            map[i&j]++
        
    
    let sum:number = 0
    for(let x of nums)
        //获取亦或值
       x ^= 0xffff let mid = x do sum += map[mid] mid = (mid-1) & x while(mid != x) return sum ;

 

 

 

以上是关于2023.3.4Leecode982按位与为零的三元组的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 982. 按位与为零的三元组

二进制的位运算

leetcode 982

这个按位与运算符如何屏蔽数字的低七位?

c语言中同或、异或怎么表示

状态压缩-动态规划