文章目录
- 题目
- 标题和出处
- 难度
- 题目描述
- 要求
- 示例
- 数据范围
- 解法
- 思路和算法
- 代码
- 复杂度分析
题目
标题和出处
标题:按位与为零的三元组
出处:982. 按位与为零的三元组
难度
6 级
题目描述
要求
给定一个整数数组 nums \texttt{nums} nums,返回按位与三元组的数量。
一个按位与三元组是一个下标三元组 (i, j, k) \texttt{(i, j, k)} (i, j, k),使得:
- 0 ≤ i < nums.length \texttt{0} \le \texttt{i} < \texttt{nums.length} 0≤i<nums.length
- 0 ≤ j < nums.length \texttt{0} \le \texttt{j} < \texttt{nums.length} 0≤j<nums.length
- 0 ≤ k < nums.length \texttt{0} \le \texttt{k} < \texttt{nums.length} 0≤k<nums.length
- nums[i] & nums[j] & nums[k] = 0 \texttt{nums[i] \& nums[j] \& nums[k]} = \texttt{0} nums[i] & nums[j] & nums[k]=0,其中 & \texttt{\&} & 表示按位与操作符
示例
示例 1:
输入: nums = [2,1,3] \texttt{nums = [2,1,3]} nums = [2,1,3]
输出: 12 \texttt{12} 12
解释:我们可以选出如下 (i, j, k) \texttt{(i, j, k)} (i, j, k) 三元组:
(i=0, j=0, k=1) \texttt{(i=0, j=0, k=1)} (i=0, j=0, k=1): 2 & 2 & 1 \texttt{2 \& 2 \& 1} 2 & 2 & 1
(i=0, j=1, k=0) \texttt{(i=0, j=1, k=0)} (i=0, j=1, k=0): 2 & 1 & 2 \texttt{2 \& 1 \& 2} 2 & 1 & 2
(i=0, j=1, k=1) \texttt{(i=0, j=1, k=1)} (i=0, j=1, k=1): 2 & 1 & 1 \texttt{2 \& 1 \& 1} 2 & 1 & 1
(i=0, j=1, k=2) \texttt{(i=0, j=1, k=2)} (i=0, j=1, k=2): 2 & 1 & 3 \texttt{2 \& 1 \& 3} 2 & 1 & 3
(i=0, j=2, k=1) \texttt{(i=0, j=2, k=1)} (i=0, j=2, k=1): 2 & 3 & 1 \texttt{2 \& 3 \& 1} 2 & 3 & 1
(i=1, j=0, k=0) \texttt{(i=1, j=0, k=0)} (i=1, j=0, k=0): 1 & 2 & 2 \texttt{1 \& 2 \& 2} 1 & 2 & 2
(i=1, j=0, k=1) \texttt{(i=1, j=0, k=1)} (i=1, j=0, k=1): 1 & 2 & 1 \texttt{1 \& 2 \& 1} 1 & 2 & 1
(i=1, j=0, k=2) \texttt{(i=1, j=0, k=2)} (i=1, j=0, k=2): 1 & 2 & 3 \texttt{1 \& 2 \& 3} 1 & 2 & 3
(i=1, j=1, k=0) \texttt{(i=1, j=1, k=0)} (i=1, j=1, k=0): 1 & 1 & 2 \texttt{1 \& 1 \& 2} 1 & 1 & 2
(i=1, j=2, k=0) \texttt{(i=1, j=2, k=0)} (i=1, j=2, k=0): 1 & 3 & 2 \texttt{1 \& 3 \& 2} 1 & 3 & 2
(i=2, j=0, k=1) \texttt{(i=2, j=0, k=1)} (i=2, j=0, k=1): 3 & 2 & 1 \texttt{3 \& 2 \& 1} 3 & 2 & 1
(i=2, j=1, k=0) \texttt{(i=2, j=1, k=0)} (i=2, j=1, k=0): 3 & 1 & 2 \texttt{3 \& 1 \& 2} 3 & 1 & 2
示例 2:
输入: nums = [0,0,0] \texttt{nums = [0,0,0]} nums = [0,0,0]
输出: 27 \texttt{27} 27
数据范围
- 1 ≤ nums.length ≤ 1000 \texttt{1} \le \texttt{nums.length} \le \texttt{1000} 1≤nums.length≤1000
- 0 ≤ nums[i] < 2 16 \texttt{0} \le \texttt{nums[i]} < \texttt{2}^\texttt{16} 0≤nums[i]<216
解法
思路和算法
最直观的做法是使用三重循环遍历数组 nums \textit{nums} nums 计算按位与为零的三元组的数量,该做法的时间复杂度是 O ( n 3 ) O(n^3) O(n3),需要优化。
以下用 ( a , b , c ) (a, b, c) (a,b,c) 表示每个三元组中的三个整数,按照顺序依次是 a a a、 b b b、 c c c。
首先枚举所有可能的二元组 ( a , b ) (a, b) (a,b),统计每个 a & b a ~\&~ b a & b 的值的计数并使用哈希表记录,枚举结束后,哈希表中包含每个三元组中的前两个整数的排列以及计数。
然后枚举所有可能的 c c c。数组 nums \textit{nums} nums 中的每个整数都可以作为三元组中的 c c c,对于每个 c c c,如果哈希表中存在整数 x x x 使得 x & c = 0 x ~\&~ c = 0 x & c=0,则存在两个整数 a a a 和 b b b 使得 a & b = x a ~\&~ b = x a & b=x,因此存在按位与为零的三元组 ( a , b , c ) (a, b, c) (a,b,c),当 c c c 固定时,按位与为零的三元组 ( a , b , c ) (a, b, c) (a,b,c) 的数量是 x x x 在哈希表中的计数。枚举结束后,即可得到按位与为零的三元组的数量。
实现方面,由于数组 nums \textit{nums} nums 中的所有整数都小于 2 16 2^{16} 216,任意两个整数的按位与结果也一定小于 2 16 2^{16} 216,因此可以使用数组代替哈希表,作为哈希表的数组的长度为数组 nums \textit{nums} nums 的最大值加 1 1 1。
代码
class Solution {public int countTriplets(int[] nums) {int count = 0;int maxNum = 0;for (int num : nums) {maxNum = Math.max(maxNum, num);}int[] map = new int[maxNum + 1];for (int num1 : nums) {for (int num2 : nums) {map[num1 & num2]++;}}for (int i = 0; i <= maxNum; i++) {if (map[i] != 0) {for (int num : nums) {if ((i & num) == 0) {count += map[i];}}}}return count;}
}
复杂度分析
-
时间复杂度: O ( n 2 + n m ) O(n^2 + nm) O(n2+nm),其中 n n n 是数组 nums \textit{nums} nums 的长度, m m m 是数组 nums \textit{nums} nums 的最大值。寻找数组 nums \textit{nums} nums 的最大值需要 O ( n ) O(n) O(n) 的时间,枚举二元组需要 O ( n 2 ) O(n^2) O(n2) 的时间,枚举三元组的最后一个数并计算按位与为零的三元组数量需要 O ( n m ) O(nm) O(nm) 的时间,因此时间复杂度是 O ( n 2 + n m ) O(n^2 + nm) O(n2+nm)。
-
空间复杂度: O ( m ) O(m) O(m),其中 m m m 是数组 nums \textit{nums} nums 的最大值。空间复杂度主要取决于哈希表,哈希表的大小是 O ( m ) O(m) O(m)。