统计按位或能得到最大值的子集数目

137 阅读1分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述

  • 给你一个整数数组 numsnums ,请你找出 numsnums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。

  • 如果数组 aa 可以由数组 bb 删除一些元素(或不删除)得到,则认为数组 aa 是数组 bb 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。

  • 对数组 aa 执行 按位或 ,结果等于 a[0]ORa[1]OR...ORa[a.length1]a[0] OR a[1] OR ... OR a[a.length - 1](下标从 00 开始)。

  • 1 <= nums.length <= 16

  • 1 <= nums[i] <= 105

  • 示例 1

输入: nums = [3,1]
输出: 2
解释: 子集按位或能得到的最大值是 3 。有 2 个子集按位或可以得到 3 :
- [3]
- [3,1]
  • 示例 2
输入: nums = [2,2,2]
输出: 7
解释: [2,2,2] 的所有非空子集的按位或都可以得到 2 。总共有 23 - 1 = 7 个子集。
  • 示例 3
输入:nums = [3,2,1,5]
输出:6
解释:子集按位或可能的最大值是 7 。有 6 个子集按位或可以得到 7 :
- [3,5]
- [3,1,5]
- [3,2,5]
- [3,2,1,5]
- [2,5]
- [2,1,5]

思路分析

  • 根据题目给出的数据范围,子集的最大数量可能为 2n12 ^ n - 1 其中 1<=n<=161<= n <= 16 ,我们就可以直接用回溯方法了。
  • 维护一个已经遍历过的子集或的最大值并进行计数,当出现比当前值更大时同时更新最大值记录和计数变量。详解见 ac 代码。

AC 代码

class Solution {
    // 记录子集或的最大值.
    int maxValue;
    // 记录子集最大值数量.
    int count;
    int n;
    public int countMaxOrSubsets(int[] nums) {
        n = nums.length;
        dfs(nums, 0, 0);
        return count;
    }

    private void dfs(int[] nums, int index, int pre) {
        if (index >= n) return;
        for (int i = index; i < n; i++) {
            int cur = pre | nums[i];
            if (cur > maxValue) { // 当前子集或值大于最大值,更新 count、maxValue.
                count = 1;
                maxValue = cur;
            } else if (cur == maxValue) { // 当前值等于最大值,更新 count.
                count++;
            }
            dfs(nums, i + 1, cur);
        }
    }
}

总结

  • 今天的 leetcode 每日一题比较常规,但是在回溯操作的时候要注意回溯判断条件,不然的话可能会出现超时的情况。