Leetcode每日一题 2044. 统计按位或能得到最大值的子集数目 DFS深搜

本文介绍了如何使用深度优先搜索(DFS)解决LeetCode的一道题目,该题要求找出数组的子集,使得子集按位或操作能得到最大值,并统计这样的子集数量。作者首先计算出数组的最大按位或值,然后通过DFS遍历所有可能的子集,记录满足条件的子集数目。文章提供了两种DFS实现方式,并分析了时间复杂度和空间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

📖本篇内容:Leetcode每日一题 2044. 统计按位或能得到最大值的子集数目 DFS深搜

📑 文章专栏:leetcode每日一题《打卡日常》

📆 最近更新:2022年3月12日 Leetcode每日一题 599. 两个列表的最小索引总和 双哈希表的合理使用一题双响~)

⭐算法仓库:小付的算法之路——Alascanfu-algorithm.git.io

🙊个人简介:一只二本院校在读的大三程序猿,本着注重基础,打卡算法,分享技术作为个人的经验总结性的博文博主,虽然可能有时会犯懒,但是还是会坚持下去的,如果你很喜欢博文的话,建议看下面一行~(疯狂暗示QwQ)

🌇 点赞 👍 收藏 ⭐留言 📝 一键三连 关爱程序猿,从你我做起

🙊写在前面🙊

来啦,来啦,日常不能少,刷题不能断,革命尚未成功,你我还需努力。

题目

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

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

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

示例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]

提示

  • 1 <= nums.length <= 16
  • 1 <= nums[i] <= 105

📝思路📝

本题考查知识点

  • 思路:最近做了很多关于dfs和bfs的题,看到这道题的第一次尝试就是深搜。
  • 但是深搜之前我们必须要知道当前数组的按位或的最大值,这个很容易求出来,只需要逐位对该数组元素或运算即可获得最大的按位或最大值

📝得到这个最大值了我们就可以进行深搜了

  • 深搜的前提是要先找到递归的跳出条件,很容易知道当咱们的元素起始坐标深搜到数组最后一个元素的时候就可以终止递归了,然后就是对当前子集是否满足其最大按位或值进行判定,记录结果值。
  • 既然如此,我们就需要知道深搜的到底是啥,然后才能写出递归深搜方向,对于每次按位或运算,可以对当前位进行或运算或者不进行或运算两种情况(即子集中是否包含该元素或者不包含该元素),对这些情况进行深搜判断,记录搜或不搜的或运算值与递归终止条件中的最大或运算值进行比较记录。

三叶姐姐的状压思路

状压DP真的很难,会慢慢掌握的~

⭐代码实现⭐

DFS深搜处理间接返回结果值

class Solution {
    int res = 0 ;
    public int countMaxOrSubsets(int[] nums) {
        int maxOfBitOr = nums[0];
        for (int i : nums)maxOfBitOr |= i;
        dfs(nums,0,0,maxOfBitOr);
        return res;
    }

    void dfs(int[] nums,int u,int val,int maxOfBitOr){
    	// 递归终止条件 跳出递归的时候
        if (nums.length == u){
        	// 对按位或运算的最大值进行判定 如果符合条件结果+1
            if (val == maxOfBitOr)
                res ++;
            // 如果不符合最大值 那说明当前子集可以直接淘汰不记录
            return ;
        }
        // 对下一个元素进行或运算 或者不进行或运算的深搜情况 即是否添加该元素到当前子集中 符合按位或运算最大值的符合条件
        dfs(nums,u+1,val,maxOfBitOr);
        dfs(nums,u+1,val|nums[u],maxOfBitOr);
    }
}
  • 时间复杂度: O( n + 2 n n + 2^n n+2n)
  • 空间复杂度: O(1) 忽略递归额外空间消耗。

DFS深搜直接返回结果值

class Solution {
    int dfs(int u ,int val,int[] nums,int maxOfBitOr){
        if (u == nums.length){
            if (val == maxOfBitOr)return 1;
            return 0;
        }
        return dfs(u+1,val,nums,maxOfBitOr)+dfs(u+1,val | nums[u] ,nums,maxOfBitOr);
    }
    public int countMaxOrSubsets(int[] nums) {
        int maxOfBitOr = 0;
        for (int i: nums)maxOfBitOr|=i;
        return dfs(0,0,nums,maxOfBitOr);
    }
}
  • 时间复杂度: O( n + 2 n n + 2^n n+2n)
  • 空间复杂度: O(1) 忽略递归额外空间消耗。

运行结果

DFS深搜
在这里插入图片描述

🙊写在最后🙊

2022-3-15今天小付打卡了哦~

美好的日出 美好的山河

都因有你存在 而璀璨 耀眼

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alascanfu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值