📌  相关文章
📜  至少一个非空子数组的按位 AND 的数字(1)

📅  最后修改于: 2023-12-03 14:57:08.978000             🧑  作者: Mango

至少一个非空子数组的按位 AND 的数字

问题描述

给定一个长度为 n 的整数数组 nums,找到谁是至少有一个非空子数组的按位与的数字。如果没有,则返回 0。

示例

输入: [2,1,3]

输出: 0

解释: 和任何一个非空的子数组的按位与的数字都为0。

输入: [2,4,8]

输出: 8

解释: [2], [4], [8], [2, 4], [4, 8], [2, 4, 8] 都是有效的子数组。它们的按位与的数字分别为 2, 4, 8, 0, 0, 8。因此最终结果为 8。

解法

这道题的关键在于对按位与的理解。对于一个非空子数组,其按位与的结果是其中所有元素按位与的结果。我们考虑如果数组中任意两个数的二进制在某一位上不同,那么这一位在按位与的结果中肯定是0。因为无论有多少个数,只需要有一个0就为0。所以,我们的目标是找到一个非空子数组,让这个子数组中所有数的二进制在某些位置上相同,然后这一些位置上的值就可以在按位与的结果中保留下来。

我们选择从1开始枚举每一位的所有可能取值,一共有32位。具体来说,我们设计一个函数 check(k),它的作用是判断是否可以找到一个非空子数组,使得这个子数组内的所有数的二进制表示第 k 位均为 1。找到任何一个满足条件的子数组都可以直接返回,这里只需要知道是否有结果即可,所以我们可以使用位运算 bitset 来记录哪些数的二进制表示中第$k$位为1。

代码实现

以下是使用 C++ 实现的代码,时间复杂度为$O(n⋅logC)$,其中 C 是数据范围内元素的最大值。

class Solution {
public:
    int check(vector<int>& nums, int k) {
        bitset<100001> s;
        for (int x : nums) {
            s[x] = true;
        }

        int mask = 1 << k;
        for (int x : nums) {
            if (s[x & mask]) {
                return true;
            }
        }
        return false;
    }

    int rangeBitwiseAnd(vector<int>& nums) {
        int res = 0;
        for (int k = 0; k <= 30; ++k) {
            if (check(nums, k)) {
                res |= 1 << k;
            }
        }
        return res;
    }
};
参考链接