算法day_3数组中的单一元素和二进制位颠倒

本文将介绍两道经典的位运算题目,这些题目经常出现在各大公司的技术面试中。通过这些题目,我们可以更好地理解位运算的应用。

题目一

数组中只出现一次的数(其它数出现 k k k 次)

来源:LeetCode 137. Single Number II 的变种题
牛客网 NC156 数组中只出现一次的数(其它数出现 k k k 次)

描述

给定一个长度为 n n n 的整型数组 arr 和一个整数 k k k ( k > 1 k > 1 k>1)。

已知 arr 中只有 1 个数出现一次,其他的数都出现 k k k 次。

请返回只出现了 1 次的数。

数据范围:

  • 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105
  • 1 < k < 100 1 < k < 100 1<k<100
  • − 2 × 1 0 9 ≤ a r r [ i ] ≤ 2 × 1 0 9 -2 \times 10^9 \leq arr[i] \leq 2 \times 10^9 2×109arr[i]2×109

📝 进阶:时间复杂度 O ( n ) O(n) O(n),空间复杂度 O ( 1 ) O(1) O(1)

示例 1

输入:

[5,4,1,1,5,1,5],3

返回值:

4

示例 2

输入:

[2,2,1],2

返回值:

1

难度:中等

解题思路

方法一:哈希表法

利用哈希表统计每个元素出现的次数,空间换时间的典型解法。

思路

  • 使用 unordered_map 统计数组中每个元素出现的次数。
  • 遍历哈希表,找到出现次数为 1 的元素。

代码实现

// 时间复杂度:O(n)
// 空间复杂度:O(n)
int foundOnceNumber(vector<int>& arr, int k) {unordered_map<int, int> frequency;for (int num : arr) {frequency[num]++;}for (const auto& [num, count] : frequency) {if (count == 1) {return num;}}return -1; // 若未找到,返回 -1
}

方法二:位运算法(推荐)

位运算的巧妙应用,空间复杂度降为 O ( 1 ) O(1) O(1)

核心思想

  • 对整数的每一位分别统计。
  • 对于每一位,统计所有数字在该位上 1 的出现次数之和。
  • 如果某一位上 1 的总数不是 k k k 的倍数,说明只出现一次的数字在该位上为 1。

详细步骤

  1. 初始化结果变量 result = 0
  2. 对于每一位 i(从 0 到 31):
    • 统计数组中所有数字在第 i 位上 1 的总个数 sum
    • 如果 sum % k != 0,将结果 result 的第 i 位置为 1。
  3. 返回结果 result

代码实现

// 时间复杂度:O(n)
// 空间复杂度:O(1)
int foundOnceNumber(vector<int>& arr, int k) {int result = 0;for (int i = 0; i < 32; i++) {int sum = 0;for (int num : arr) {sum += (num >> i) & 1; // 获取 num 在第 i 位的值}if (sum % k != 0) {result |= (1 << i); // 将第 i 位置为 1}}return result;
}

注意事项

  • 处理负数:由于负数在计算机中以补码形式存储,右移时需要注意符号扩展,可以使用无符号数来避免问题。
  • 优化:若数组中存在负数,需将 num 转换为 unsigned int 进行位运算。

改进代码

int foundOnceNumber(vector<int>& arr, int k) {int result = 0;for (int i = 0; i < 32; i++) {int sum = 0;for (int num : arr) {unsigned int temp = num;sum += (temp >> i) & 1;}if (sum % k != 0) {result |= (1 << i);}}return result;
}

方法三:状态机法(特殊情况下适用)

k = 3 k=3 k=3 时,可使用状态机法进一步优化。

代码示例

int singleNumber(vector<int>& nums) {int ones = 0, twos = 0;for (int num : nums) {ones = (ones ^ num) & ~twos;twos = (twos ^ num) & ~ones;}return ones;
}

说明

  • 该方法利用二进制位的状态转换,适用于某些特定的 k k k 值。

相关知识点

  • 位运算基础

    • 按位与 &:两个位都为 1,则结果为 1,否则为 0。
    • 按位或 |:两个位只要有一个为 1,则结果为 1。
    • 按位异或 ^:两个位不同时结果为 1,相同时结果为 0。
    • 按位取反 ~:将位的值取反,0 变 1,1 变 0。
    • 左移 <<:将二进制位向左移动,低位补 0。
    • 右移 >>:将二进制位向右移动,移出的位舍弃。
  • 位运算应用

    • 异或运算特点
      • 任何数与 0 异或结果为其本身。
      • 任何数与自身异或结果为 0。
    • 位掩码:通过与特定的掩码进行位运算,实现对某些位的操作。

题目二

190. 颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

提示

  • 在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,但不影响实际的二进制位操作。

示例 1

输入:

n = 00000010100101000001111010011100

输出:

964176192 (00111001011110000010100101000000)

解释:

  • 输入的二进制串表示无符号整数 43261596
  • 返回的二进制串表示无符号整数 964176192

示例 2

输入:

n = 11111111111111111111111111111101

输出:

3221225471 (10111111111111111111111111111111)

解释:

  • 输入的二进制串表示无符号整数 4294967293
  • 返回的二进制串表示无符号整数 3221225471

难度:简单

解题思路

我们需要将给定的 32 位无符号整数的二进制位按位翻转。

方法一:逐位翻转

思路

  • 初始化结果变量 result = 0
  • 遍历给定整数的每一位(共 32 位):
    1. result 左移一位,为下一位腾出位置。
    2. 取出 n 的最低位 (n & 1),加入到 result 中。
    3. n 右移一位,准备处理下一位。
  • 返回结果 result

代码实现

uint32_t reverseBits(uint32_t n) {uint32_t result = 0;for(int i = 0; i < 32; i++){result <<= 1;        // 左移一位result |= (n & 1);   // 加入最低位n >>= 1;             // 右移一位}return result;
}

方法二:位操作优化(分治法)

思路

  • 使用位操作技巧,分组交换二进制位,达到翻转的目的。
  • 具体步骤:
    1. 将高 16 位与低 16 位交换。
    2. 将每个 16 位中的高 8 位与低 8 位交换。
    3. 将每个 8 位中的高 4 位与低 4 位交换。
    4. 将每个 4 位中的高 2 位与低 2 位交换。
    5. 将每个 2 位中的高 1 位与低 1 位交换。

代码实现

uint32_t reverseBits(uint32_t n) {n = (n >> 16) | (n << 16); // 交换高低 16 位n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); // 交换每个 16 位内的高低 8 位n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); // 交换每个 8 位内的高低 4 位n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); // 交换每个 4 位内的高低 2 位n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); // 交换每个 2 位内的高低 1 位return n;
}

解释

  • 使用掩码和移位操作,实现不同位数的高低位交换,从而达到整体翻转的效果。

方法三:查表法(缓存法)

思路

  • 将 32 位分成 4 个字节(8 位),预先计算 256( 2 8 2^8 28)个可能的字节翻转结果,存入数组。
  • 遍历每个字节,利用查表快速获取翻转结果。

代码实现

static uint8_t reverseByte(uint8_t byte) {byte = (byte >> 4) | (byte << 4);byte = ((byte & 0xCC) >> 2) | ((byte & 0x33) << 2);byte = ((byte & 0xAA) >> 1) | ((byte & 0x55) << 1);return byte;
}uint32_t reverseBits(uint32_t n) {static unordered_map<uint8_t, uint8_t> cache;uint32_t result = 0;for (int i = 0; i < 4; ++i) {uint8_t byte = (n >> (i * 8)) & 0xFF;if (cache.find(byte) == cache.end()) {cache[byte] = reverseByte(byte);}result |= (uint32_t)(cache[byte]) << ((3 - i) * 8);}return result;
}

说明

  • 此方法适合大量多次调用的情况,使用缓存可以提高效率。

相关知识点

  • 位操作技巧

    • 掩码的使用:通过与特定的掩码进行按位与操作,提取或清零特定位。
    • 位分组交换:通过移位和掩码,实现位的分组交换。
  • 性能优化

    • 查表法:预先计算可能的结果,利用空间换取时间。

参考资料

  1. 《算法导论》第 2 章 基础知识
  2. LeetCode 官方题解
  3. 位运算技巧总结

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

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

相关文章

Windows开启IIS后依然出现http error 503.the service is unavailable

问题背景 已启用IIS服务&#xff0c;配置步骤可以参考Windows10 IIS Web服务器安装配置 问题描述 在这一步浏览网站时&#xff0c;并没有出现默认首页&#xff0c;而是 http error 503 the service is unavailable 问题解决 参考 成功解决http error 503.the service is un…

mapbox基础,加载mapbox官方地图

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;mapbox 从入门到精通 文章目录 一、&#x1f340;前言1.1 ☘️mapboxgl.Map 地图对象…

一体式IO模块:打印机加工产线国产化降本增效的新利器

在当今全球化的市场竞争中&#xff0c;打印机制造行业面临着前所未有的挑战与机遇。为了提升生产效率、降低成本&#xff0c;并加速国产化进程&#xff0c;各大打印机制造商纷纷寻求技术创新与升级。明达技术自研推出的MR20一体式IO模块作为工业自动化领域的核心组件&#xff0…

公交车信息管理系统:实现交通数据的智能化处理

概述 在对系统进行设计之前&#xff0c;需要对选题进行需求分析、可行性分析、流程分析、数据字典等内容。根据需求分析阶段&#xff0c;大致确定用户使用系统所需要具有的功能模块需求&#xff0c;由此规划出系统需要设计的相关功能模块。根据可行性分析阶段&#xff0c;确定系…

C++的侵入式链表

非侵入式链表 非侵入式链表是一种链表数据结构&#xff0c;其中每个元素&#xff08;节点&#xff09;并不需要自己包含指向前后节点的指针。链表的结构和节点的存储是分开的&#xff0c;链表容器会单独管理这些指针。 常见的非侵入式链表节点可以由以下所示&#xff0c;即&a…

绕组识别标签规范

有标签名称的要标记&#xff0c;没有的不用标记 需要标注的工具、器材 图像中文名称标签名称od脱模剂watering can2铁铲shovel1记号笔&#xff0c;白色着重标bluepen/whitepen6纸质标签label3钢尺scale5玻璃纤维带&#xff08;卷&#xff09;红色网格布red grid4白色网格布wh…

关于uni-forms组件的bug【提交的字段[‘*‘]在数据库中并不存在】

问题&#xff1a;在使用 uni-forms校验的时候&#xff0c;出来的一个问题&#xff0c;这个字段都没有设置校验的规则&#xff0c;不知道什么原因就出现了下图的问题&#xff1a; 解决办法&#xff1a; 在uni-forms-item 添加key 值就解决了 原因不知道&#xff0c;有大佬发现…

解析mysqlbinlog

一、前置设置 ps -ef | grep mysql 查看mysql进程对应的安装目录 需设置mysql binlog日志模式为 ROW 二、执行命令 [rootlocalhost bin]# mysqlbinlog --verbose --base64-outputdecode-rows /usr/local/mysql/data/binlog.000069 > 1.sql 查看文件具体内容

WebRTC服务质量(08)- 重传机制(05) RTX机制

一、前言&#xff1a; RTX协议&#xff08;Retransmission&#xff0c;即重传协议&#xff09;是 WebRTC 中用于处理丢包恢复的一部分。由于网络通信中的丢包不可避免&#xff0c;WebRTC RTP协议栈支持多种丢包恢复机制&#xff0c;其中之一便是通过RTX协议实现的重传机制。 …

电脑出现 0x0000007f 蓝屏问题怎么办,参考以下方法尝试解决

电脑蓝屏是让许多用户头疼的问题&#xff0c;其中出现 “0x0000007f” 错误代码更是较为常见且棘手。了解其背后成因并掌握修复方法&#xff0c;能帮我们快速恢复电脑正常运行。 一、可能的硬件原因 内存问题 内存条长时间使用可能出现物理损坏&#xff0c;如金手指氧化、芯片…

用C#(.NET8)开发一个NTP(SNTP)服务

完整源码&#xff0c;附工程下载&#xff0c;工程其实也就下面两个代码。 想在不能上网的服务器局域网中部署一个时间服务NTP&#xff0c;当然系统自带该服务&#xff0c;可以开启&#xff0c;本文只是分享一下该协议报文和能跑的源码。网上作为服务的源码不太常见&#xff0c;…

java web springboot

0. 引言 SpringBoot对Spring的改善和优化&#xff0c;它基于约定优于配置的思想&#xff0c;提供了大量的默认配置和实现 使用SpringBoot之后&#xff0c;程序员只需按照它规定的方式去进行程序代码的开发即可&#xff0c;而无需再去编写一堆复杂的配置 SpringBoot的主要功能…

工厂防静电监控系统设备静电监控仪的关键作用

在现代工业生产中&#xff0c;静电问题日益凸显&#xff0c;尤其是在电子、半导体、精密机械加工等领域&#xff0c;静电可能引发诸如电子元件击穿、产品吸附灰尘杂质、设备故障乃至火灾爆炸等严重后果。为了有效防控静电危害&#xff0c;工厂防静电监控系统应运而生&#xff0…

重温设计模式--状态模式

文章目录 状态模式&#xff08;State Pattern&#xff09;概述状态模式UML图作用&#xff1a;状态模式的结构环境&#xff08;Context&#xff09;类&#xff1a;抽象状态&#xff08;State&#xff09;类&#xff1a;具体状态&#xff08;Concrete State&#xff09;类&#x…

Java代码覆盖率super-jacoco

项目流程 项目架构 部署步骤 注意&#xff1a;一定要用Linux服务器部署&#xff0c;不要用Windows 准备Linux服务器环境 安装好JDK1.8 安装好git 安装和配置好Maven3.6&#xff0c;或3.6以下 安装MySQL数据库&#xff08;尽量不用8版本&#xff0c;就用5.7、5.8版本&#xf…

Day1 苍穹外卖前端 Vue基础、Vue基本使用方式、Vue-router、Vuex、TypeScript

目录 1.VUE 基础回顾 1.1 基于脚手架创建前端工程 1.1.1 环境要求 1.1.2 脚手架创建项目 1.1.3 工程结构 1.1.4 启动前端服务 1.2 vue基本使用方式 1.2.1 vue 组件 1.2.2 文本插值 1.2.3 属性绑定 1.2.4 事件绑定 1.2.5 双向绑定 1.2.6 条件渲染 1.2.7 跨域问题 1.2.8 axios 1.…

重温设计模式--中介者模式

中介者模式介绍 定义&#xff1a;中介者模式是一种行为设计模式&#xff0c;它通过引入一个中介者对象来封装一系列对象之间的交互。中介者使得各个对象之间不需要显式地相互引用&#xff0c;从而降低了它们之间的耦合度&#xff0c;并且可以更方便地对它们的交互进行管理和协调…

Redis篇--常见问题篇7--缓存一致性2(分布式事务框架Seata)

1、概述 在传统的单体应用中&#xff0c;事务管理相对简单&#xff0c;通常使用数据库的本地事务&#xff08;如MySQL的BEGIN和COMMIT&#xff09;来保证数据的一致性。然而&#xff0c;在微服务架构中&#xff0c;由于每个服务都有自己的数据库&#xff0c;跨服务的事务管理变…

如何评估一个股票API接口

评估一个股票 API 接口的质量&#xff0c;可以从以下几个方面进行&#xff1a; 数据准确性 行情数据&#xff1a;实时价格、历史价格、成交量、成交额等数据应与证券交易所或权威金融数据提供商的官方数据高度一致&#xff0c;确保没有明显的错误。财务数据&#xff1a;企业的…

某集团GIF动态验证码识别

注意&#xff0c;本文只提供学习的思路&#xff0c;严禁违反法律以及破坏信息系统等行为&#xff0c;本文只提供思路 如有侵犯&#xff0c;请联系作者下架 本文识别已同步上线至OCR识别网站&#xff1a; http://yxlocr.nat300.top/ocr/other/16 最近某集团更新了验证码&#x…