【LeetCode 热题 100】78. 子集——(解法三)位运算

Problem: 78. 子集
题目:给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

文章目录

  • 整体思路
  • 完整代码
  • 时空复杂度
    • 时间复杂度:O(N * 2^N)
    • 空间复杂度:O(N) (不考虑输出数组)

整体思路

这段代码同样旨在解决 “子集 (Subsets)” 问题。与前面基于回溯/DFS的递归解法不同,此版本采用了一种完全不同的、基于 位掩码(Bitmask) 的迭代方法。这种方法非常巧妙,它将“生成子集”的问题与“二进制数的表示”完美地对应起来。

算法的核心思想是:

  1. 子集与二进制数的映射关系

    • 一个包含 n 个元素的集合,其所有子集的数量是 2^n
    • 巧合的是,从 02^n - 1,也正好有 2^n 个不同的整数。
    • 我们可以将这 n 个元素与一个 n 位的二进制数的每一位进行一一对应。例如,nums = [a, b, c]n=3。我们可以用一个 3 位的二进制数来表示一个子集:
      • 第 0 位对应元素 a
      • 第 1 位对应元素 b
      • 第 2 位对应元素 c
    • 规则:如果二进制数的某一位是 1,则表示对应的元素被选中加入子集;如果是 0,则表示不选
    • 示例
      • 二进制 000 (十进制 0) -> {} (空集)
      • 二进制 001 (十进制 1) -> {a}
      • 二进制 010 (十进制 2) -> {b}
      • 二进制 101 (十进制 5) -> {a, c}
      • 二进制 111 (十进制 7) -> {a, b, c}
    • 这样,从 02^n - 1 的每一个整数,都唯一地对应着一个子集。
  2. 算法实现步骤

    • 外层循环:算法的主体是一个 for 循环,它从 i = 0 遍历到 (1 << n) - 1。这里的 (1 << n) 就是 2^n。这个循环变量 i 就充当了位掩码,它的二进制表示决定了当前要生成哪个子集。
    • 内层循环与位运算
      • 对于每一个位掩码 i,算法进入一个内层循环,从 j = 0n-1,检查 i 的每一位。
      • 检查第 j:通过位运算 (i >> j & 1) == 1 来检查 i 的第 j 位是否为 1。
        • i >> j: 将 i 右移 j 位,使得原来的第 j 位移动到最右边(第 0 位)。
        • & 1: 将右移后的结果与 1 进行按位与操作。如果原来的第 j 位是 1,结果就是 1;如果是 0,结果就是 0
      • 构建子集:如果检查结果为 1,说明 nums[j] 这个元素应该被包含在当前子集中,于是将其加入到临时的 subset 列表中。
    • 收集结果:内层循环结束后,subset 列表就构建完毕了,将其加入到最终的结果列表 ans 中。

通过这种方式,算法以一种确定性的、非递归的方式,系统地生成了所有 2^n 个子集。

完整代码

class Solution {/*** 计算给定数组的所有子集(幂集)。* (位掩码迭代法)* @param nums 不含重复元素的整数数组* @return 包含所有子集的列表*/public List<List<Integer>> subsets(int[] nums) {int n = nums.length;// 预先设定ArrayList的容量为 2^n,可以提高性能,避免多次内部扩容。// (1 << n) 是 2^n 的高效写法。List<List<Integer>> ans = new ArrayList<>(1 << n);// 步骤 1: 外层循环遍历所有可能的子集,用整数 0 到 2^n - 1 作为位掩码。for (int i = 0; i < (1 << n); i++) {// 为每个位掩码创建一个新的子集列表。List<Integer> subset = new ArrayList<>();// 步骤 2: 内层循环检查位掩码 i 的每一位,以确定哪些元素应加入子集。for (int j = 0; j < n; j++) {// 关键的位运算:检查 i 的第 j 位是否为 1。// (i >> j) 将 i 的第 j 位移到最右边。// (& 1)   检查最右边一位是否为 1。if ((i >> j & 1) == 1) {// 如果第 j 位为 1,则将 nums[j] 加入到当前子集中。subset.add(nums[j]);}}// 将构建好的子集加入到最终结果列表中。ans.add(subset);}return ans;}
}

时空复杂度

时间复杂度:O(N * 2^N)

  1. 外层循环for (int i = 0; i < (1 << n); i++) 执行 2^N 次。
  2. 内层循环for (int j = 0; j < n; j++) 执行 N 次。
  3. 循环内部操作:位运算和 subset.add() 都是 O(1) 的操作。

综合分析
算法的总操作次数是外层循环次数乘以内层循环次数,即 2^N * N
因此,总的时间复杂度为 O(N * 2^N)。这与回溯法的时间复杂度量级是相同的,因为问题的内在计算量就是这么多。

空间复杂度:O(N) (不考虑输出数组)

  1. 主要存储开销:我们分析的是额外辅助空间
    • List<Integer> subset: 在每次外层循环中,都会创建一个临时的 subset 列表。在任意时刻,只有一个 subset 列表存在于内存中。这个列表的最大长度为 N(当位掩码为 11...1 时)。因此,这部分空间是 O(N)
    • 其他变量 n, i, j 都是常数空间。

综合分析
如果不考虑存储最终结果的 ans 列表(其空间为 O(N * 2^N)),算法所需的额外辅助空间主要由临时的 subset 列表决定。因此,其空间复杂度为 O(N)

参考灵神

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/90229.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/90229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

XCKU035‑1SFVA784C Xilinx FPGA KintexUltraScale AMD

XCKU035‑1SFVA784C 属于 Xilinx Kintex UltraScale 系列&#xff0c;基于领先的 20 nm FinFET 技术制程&#xff0c;旨在为中高端应用提供卓越的性能与功耗平衡。该器件采用 784‑ball Fine‑pitch BGA&#xff08;SFVA784&#xff09;封装&#xff0c;速度等级‑1&#xff0…

Encore.ts:下一代高性能 TypeScript 后端框架的崛起

在 Node.js 生态系统中&#xff0c;后端框架的选择直接影响 API 的性能、开发体验和可维护性。近年来&#xff0c;Elysia.js、Hono、Fastify 等框架凭借各自的优化策略崭露头角&#xff0c;而 Encore.ts 则凭借 Rust TypeScript 混合架构&#xff0c;在性能上实现了质的飞跃。…

【IP地址】IP归属地查询驱动企业实时战略调整

动态市场感知与资源调度优化​ IP归属地的实时分析为企业提供了市场需求的动态变化图。 基于实时数据处理框架&#xff0c;企业可将IP归属地数据与用户访问量、转化率等指标关联计算&#xff0c;生成区域市场活跃度热力图。 当某区域IP访问量在1小时内激增300%且停留时长提升至…

[Bug | Cursor] import error: No module named ‘data‘

import error: No module named ‘data’ Folder Structure root folder data folder dataloader.py src folder train.py <- where we try to import the dataloader.pyFailed Script ROOT_DIR Path(__file__).parent.parent os.chdir(ROOT_DIR) print(f"Using root…

#Linux权限管理:从“Permission denied“到系统安全大师

引入 Linux 作为多用户系统&#xff0c;权限是系统安全的第一道防线。不合理的权限设置可能导致&#xff1a; 敏感文件泄露&#xff08;如数据库密码被读取&#xff09;误删核心数据&#xff08;目录写权限失控&#xff09;权限漏洞被利用&#xff08;如 SUID 提权攻击&#…

电脑重置一次对电脑伤害大吗

在日常使用电脑的过程中&#xff0c;很多用户或多或少都遇到过系统卡顿、软件冲突、病毒入侵等问题。当电脑变得“越来越慢”或频繁出错时&#xff0c;一些用户会考虑“重置电脑”&#xff0c;也就是将电脑恢复到出厂设置。但不少人心中也有疑问&#xff1a;重置电脑一次&#…

CSP-J系列【2024】P11229 [CSP-J 2024] 小木棍题解

题目描述小 S 喜欢收集小木棍。在收集了 n 根长度相等的小木棍之后&#xff0c;他闲来无事&#xff0c;便用它们拼起了数字。用小木棍拼每种数字的方法如下图所示。现在小 S 希望拼出一个正整数&#xff0c;满足如下条件&#xff1a;拼出这个数恰好使用 n 根小木棍&#xff1b;…

C# 继承 虚方法

继承 虚方法 &#xff08;重写&#xff09; virtual 虚方法的关键字 override 重写的关键字 练习&#xff1a; 继承 继承&#xff1a;很多类有相似的数据 相同的属性 相同的方法 也有不同的 这个时候就可以使用继承 让多个类去继承自某个具有相同数据的基类(父类) 这…

Java 堆(优先级队列)

文章目录优先级队列模拟实现优先级队列向下调整建堆向上调整建堆堆的删除priorityQueue构造方法大根堆和小根堆的向上调整比较方法扩容面试题堆排序优先级队列 priorityqueue&#xff1a;底层是一颗完全二叉树 小根堆&#xff1a;根比左右孩子都小大根堆&#xff1a;根比左右…

在.NET Core API 微服务中使用 gRPC:从通信模式到场景选型

目录 一、gRPC 基础&#xff1a;为什么它适合微服务&#xff1f; 二、gRPC 的四种通信模式及.NET Core 实现 1. 一元 RPC&#xff08;Unary RPC&#xff09;&#xff1a;最基础的请求 - 响应模式 2. 服务器流式 RPC&#xff08;Server Streaming RPC&#xff09;&#xff1…

HTML零基础快速入门教程(详细篇)

本文详细介绍HTML零基础快速入门的基础知识&#xff0c;包括HTML的介绍、语言的一些实际作用、语法规范注意&#xff0c;如标签结构、标签属性、大小写不敏感等&#xff0c;还介绍了HTML文件的具体书写规则&#xff0c;如文件扩展名、文档类型声明和HTML结构以及具体的一些HTML…

LLM评测框架Ragas:SQL指标(解决了Ollama推理框架不支持的问题)

SQL类的度量指标是指运行SQL后的结果和预期之间的一个度量值。 datacompy score datacompy score 使用DataCompy(一个比较pandas的数据格式的python类,所以需要按照datacompy:pip install datacompy),默认是按照rows比较,也可以设置按照columns比较,这个事通过mode参数…

ubuntu24 ros2 jazzy

安装2 software & update 选择其它 安装 一、前提准备 检查操作系统版本&#xff1a; 确保你的系统版本是Ubuntu 24.04。你可以通过运行lsb_release -a命令来检查当前的系统版本。 设置UTF-8支持&#xff1a; ROS 2需要UTF-8编码支持。你可以通过以下命令来检查和设置UTF…

设备虚拟化技术

设备虚拟化技术概述设备虚拟化技术通过软件模拟物理硬件设备&#xff0c;使多个操作系统或应用程序能够共享同一台物理设备。它广泛应用于云计算、服务器整合和测试环境等领域。核心目标是提高资源利用率、隔离性和灵活性。•当接入的用户数增加到原交换机端口密度不能满足接入…

开发避坑短篇(3):解决@vitejs plugin-vue@5.0.5对Vite^5.0.0的依赖冲突

异常信息 # npm resolution error reportWhile resolving:system3.8.8 Found: vite6.2.3 node_modules/vitedev vite"6.2.3" from the root projectCould not resolve dependency: peer vite"^5.0.0" from vitejs/plugin-vue5.0.5 node_modules/vitejs/plu…

k8s快速部署(亲测无坑)

文章目录k8s快速部署&#xff08;亲测无坑&#xff09;一、网络划分二、CentOS7设置 标题固定IP和阿里云YUM源三、主机环境配置四、虚拟机的拷贝五、安装docker(每台主机都需要安装)六、安装kubelet,kubeadm,kubectl(每台机器都需要执行)遇到的问题参考文档k8s快速部署&#xf…

简易RAG问答引擎的构建与体验

RAG&#xff08;检索增强生成&#xff09;是结合检索与生成式 AI 的技术框架。核心逻辑是先从外部知识库精准检索相关信息&#xff0c;再将其作为上下文输入大模型生成回答。技术上依赖检索引擎&#xff08;如向量数据库、BM25&#xff09;、大语言模型&#xff08;如 GPT、LLa…

C++11特性学习 Day1

nullptr对于c中null (void*)0&#xff0c;所以在为函数传参传入0时&#xff0c;无法清楚地分辨是int类型的0还是指的是空指针null在C11中清晰的将空指针变为了nullptr&#xff0c;0专指int型的数字0override关键字在子类中对父类的函数的覆写之后加上override关键字&#xff0…

微算法科技(NASDAQ: MLGO)探索优化量子纠错算法,提升量子算法准确性

随着量子计算技术的飞速发展&#xff0c;量子计算机在解决复杂计算问题上的潜力日益显现。然而&#xff0c;量子计算面临的一个重大挑战是量子比特的脆弱性&#xff0c;即量子比特容易受到环境噪声和干扰的影响&#xff0c;导致量子态的塌缩和计算结果的错误。微算法科技&#…

MongoDB数据库详解-针对大型分布式项目采用的原因以及基础原理和发展-卓伊凡|贝贝|莉莉

MongoDB数据库详解-针对大型分布式项目采用的原因以及基础原理和发展-卓伊凡|贝贝|莉莉由于老产品即时通讯私有化软件就是采用MongoDB &#xff0c;但是版本实在太低&#xff0c;要做大更新&#xff0c;其次针对10年前完美运营的项目来到10年后的现在就不一定行&#xff0c;优雅…