Leetcode 982

154 阅读1分钟

求数组中任意三个数与为0的组合数目

题目会输入一个整数数组, 可以任意选择三个索引 i,j,k, 其中 i,j,k 可以任意选择, 可以重复, 也没有顺序要求。 问, 总共有多少种 i,j,k 的排列, 可以让 a[i] & a[j] & a[k] = 0?

题目对数据的大小做了说明: 其中, 1 <= A.length <= 1000 另外, 0 <= A[i] < 2^16

思考 1 最直观的方法是直接遍历 O(nnn) 2 因为是根据 dp 刷的题目,这里肯定可以使用 dp 来解决,dp 最重要的就是找到状态转移方程 可以利用 dp[i] 表示 A 中两个&是 i 的数目,则可以继续遍历 dp 和 A,只要两者&等于 0,就可以相加

3 时间复杂度 O(2^16 * n)空间复杂度O(2^16)

/**
 * @param {number[]} A
 * @return {number}
 */
// export default (A) => {
//   let count = 0;
//   for (let i = 0; i < A.length; i++) {
//     for (let j = 0; j < A.length; j++) {
//       for (let k = 0; k < A.length; k++) {
//         if ((A[i] & A[j] & A[k]) === 0) {
//           count++;
//         }
//       }
//     }
//   }
//   return count;
// };

export default (A) => {
  let res;
  const n = 1 << 16;
  let dp = new Array(n).fill(0);
  // 暂时缓存A中两个数字&的结果
  for (let i = 0; i < A.length; i++) {
    for (let j = 0; j < A.length; j++) {
      dp[A[i] & A[j]]++;
    }
  }
  // 如果两个数字&的结果是0,则肯定是有dp[0] * A.length个结果
  res = dp[0] * A.length;
  for (let i = 1; i < dp.length; i++) {
    // 如果dp[i] = 0,说明暂存的没有i
    if (dp[i] === 0) {
      continue;
    }
    for (let j = 0; j < A.length; j++) {
      if ((i & A[j]) === 0) {
        res += dp[i];
      }
    }
  }
  return res;
};