【算法题-困难】按位与为零的三元组
困难算法题,按位与为零的三元组,使用 JavaScript 语言编写
题目
给你一个整数数组 nums ,返回其中 按位与三元组 的数目。
按位与三元组 是由下标 (i, j, k) 组成的三元组,并满足下述全部条件:
- 0 <= i < nums.length
- 0 <= j < nums.length
- 0 <= k < nums.length
- nums[i] & nums[j] & nums[k] == 0 ,其中 & 表示按位与运算符。
提示:
- 1 <= nums.length <= 1000
- 0 <= nums[i] < 2^16
注意:时间复杂度是 O(n^3)的算法,会超出时间限制。
输入格式
整数数组nums,以”,”分隔字符串形式作为输入
输出格式
一个数字,字符串形式
输入样例
2,1,3
输出样例
12
分析
要解决这个问题,我们需要找到一种比 O(n^3) 更高效的方法。我们可以利用按位与运算的性质和哈希表来优化算法。
预处理两两组合的按位与结果:我们可以先计算所有可能的两两组合的按位与结果,并将这些结果存储在一个哈希表中。 检查第三个数:对于每个数 nums[k],我们可以检查它与哈希表中所有按位与结果的组合是否等于 0。如果是,则说明存在一个三元组 (i, j, k) 满足条件。
解答
// 这是题目要求的输入格式
let inputs = `2,1,3`;
function countTriplets(nums) {
const n = nums.length;
const countMap = new Map();
// 预处理两两组合的按位与结果
for (let i = 0; i < n; i++) {
for (let j = 0; j < n; j++) {
const andResult = nums[i] & nums[j];
countMap.set(andResult, (countMap.get(andResult) || 0) + 1);
}
}
let count = 0;
// 检查第三个数
for (let k = 0; k < n; k++) {
for (const [andResult, freq] of countMap) {
// (andResult & nums[k]),两边要加括号,否则优先级没有 & 高
if ((andResult & nums[k]) === 0) {
count += freq;
}
}
}
return count;
}
// 不使用 .map(Number) 的话测试用例会超时
console.log(countTriplets(inputs.split(',').map(Number)));
解释
- 预处理两两组合的按位与结果:我们遍历数组中的每一对元素 (nums[i], nums[j]),计算它们的按位与结果,并将结果存储在哈希表 countMap 中。哈希表的键是按位与结果,值是该结果出现的次数。
- 检查第三个数:我们遍历数组中的每一个元素 nums[k],并检查它与哈希表中所有按位与结果的组合是否等于 0。如果是,则说明存在一个三元组 (i, j, k) 满足条件。我们将这些组合的频次累加到 count 中。
- 返回结果:最终返回满足条件的三元组的数量 count。
通过这种方法,我们可以有效地计算出满足条件的按位与三元组的数目,时间复杂度为 O(n^2),比 O(n^3) 更高效。
留下评论