leetCode 137. 只出现一次的数字 II + 位运算 + 模3加法器 + 真值表(数字电路) + 有限状态机

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。你必须设计并实现线性时间复杂度的算法且使用常数级空间来解决此问题。



  • 常规解法:哈希(hash)

使用哈希映射统计数组中每个元素的出现次数,对于哈希映射中的每个键值对,键表示一个元素,值表示其出现的次数。在统计完成后,遍历哈希映射即可找出只出现一次的元素

class Solution {
public:// 哈希表int singleNumber(vector<int>& nums) {unordered_map<int,int> mp;for(const int &num:nums) {++mp[num];}int ans = 0;// for(auto &it:mp) //     if(it.second==1) return it.first;for(auto [x,cnt]:mp) if(cnt==1) {ans=x;break;}return ans;}
};
  • 时间复杂度:O(n),其中 n 是数组的长度。
  • 空间复杂度:O(n),哈希映射中包含最多 ⌊n/3⌋+1 个元素,即需要的空间为 O(n)

****************************************** 进入本文正题****************************************** 

(1)实现「统计每个比特位的 1 的个数」

class Solution {
public:// 模3加法 方法1:统计每个比特位的1的个数int singleNumber(vector<int>& nums) {int ans = 0 ;for(int i=0;i<32;i++) {int cnt = 0;for(const int& x : nums) {cnt += (x>>i & 1);}ans |= (cnt%3) << i;}return ans;}
};
(2)位运算,设计 "模3加法器"

可以使用一个「黑盒」存储当前遍历过的所有整数,「黑盒」的第 i 位为{ 0, 1, 2 }三者之一表示当前遍历过的所有整数的第 i 位之和除以3的余数。但由于二进制表示中只有 0 和 1 而没有 2,因此我们可以考虑在「黑盒」中使用两个整数来进行存储,即:

黑盒中存储了两个整数 a 和 b,且会有三种情况:

  • a 的第 i 位为 0 且 b 的第 i 位为 0,表示 0
  • a 的第 i 位为 0 且 b 的第 i 位为 1,表示 1
  • a 的第 i 位为 1 且 b 的第 i 位为 0,表示 2

当遍历到一个新的整数 x 时,对于 x 的第 ix_{i}

  • 如果 x_{i}=0,那么 a 和 b 的第 i 位不变;
  • 如果 x_{i}=1,那么 a 和 b 的第 i 位按照 (00) -> (01) -> (10) -> (00) 这一循环进行变化

分析:本题思路和 single Number 一样,同样考虑一个比特位的情况,这里需要对这个比特进行计数到 3 时归 0,也就是说需要一个模3加法器。但是没有现成的加法器,那么需要自己构造一个能位运算的模3加法器

思考:计数器要经历 0,1,2 这三个状态,但是一个比特位只能表示两个状态,怎么办呢?此时我们可以扩展一个比特,即用两个比特来保存位计数器的三个状态。假设 b 为低位, a 为高位。c 代表x_{i}x 的第 i 位:x_{i})用 ab 两个比特位来作为这一位 c 的位计数器。

  • 当这一位 c 来 1 时位计数器就进行状态转换,否则维持原状态,而最后的结果会保存在计算器的低位 b 里
  • 当 c 为 0 时不会变化,那么状态不发生变化

注:a1 和 b1 表示 a,b 的下一个状态 ,c 代表 x_{i}x 的第 i 位:x_{i}),a' 表示 a非,b' 表示 b非

1.「同时计算」

a=a' bc+ab'c'

b=a'b'c+a'bc'=a'(b'c+bc')  =a'(b\bigoplus c)

转成代码:

a = (~a & b & c) | (a & ~b & ~c)b = (~a) & (b ^ c)

C++代码:

class Solution {
public:// 模3加法 方法2:用位运算实现int singleNumber(vector<int>& nums) {int a=0,b=0;for(const int& x:nums) {int tmp_a = a;a = (a^x) & (a|b);b = (b^x) & (~tmp_a);}return b; }
};

2.「分别计算」

  • 发现「同时计算」中计算 b 的规则较为简单,而 a 的规则较为麻烦
  • 可改为「分别计算」,即先计算出 b,再拿新的 b 值计算 a

b=a'b'c+a'bc'=a'(b'c+bc')  =a'(b\bigoplus c)

a=a'b'c+ab'c'=b'(a'c+ac') =b'(a\bigoplus c)

转成代码:

b = (~a) & (b ^ c) // 所以,先计算出ba = (~b) & (a ^ c) // 再计算a

C++代码:

class Solution {
public:// 模3加法 方法2:用位运算实现int singleNumber(vector<int>& nums) {int a=0,b=0;for(const int& x:nums) {b = (b^x) & (~a);a = (a^x) & (~b);}return b; }
};
  • 时间复杂度:O(n),其中 n 为 nums 的长度
  • 空间复杂度:O(1),仅用到若干额外变量
(3)有限状态自动机

对于异或(模2加法)来说,把一个数不断地异或1,相当于在 0 和 1 之间不断转换,即:

0->1->0->1->...

 类似地,模 3 加法 就是在 0, 1, 2, 之间不断转换,即:

0->1->2->0->1->2->...

  • a = 0b = 0 时,a 必须保持不变,仍然为 0
  • a = 1 时(此时 b 一定是 0),必须保持不变,仍然为 0

【注】c 代表 x_{i}x 的第 i 位 : x_{i}),a' 表示 a非b' 表示 b非

if(a == 0) {if(c == 0) {b=b;}if(c == 1) {b=~b;}
}if(a == 1) {b=0;
}

引入异或运算,当 if(a == 0) 时,

b = c'b + cb' = b\oplus c 

转成代码:

if(a == 0) b = b ^ c;

那么可以将上述拆分简化为:

if(a == 0) b = b ^ c;
if(a == 1) b = 0;

引入与运算,继续简化:

b = a'(b\oplus c)

转成代码:

b = (~a) & (b ^ c);

a = (~b) & (a ^ c);

推荐和参考文章:

137. 只出现一次的数字 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/single-number-ii/solutions/2482832/dai-ni-yi-bu-bu-tui-dao-chu-wei-yun-suan-wnwy/137. 只出现一次的数字 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/single-number-ii/solutions/8944/single-number-ii-mo-ni-san-jin-zhi-fa-by-jin407891/137. 只出现一次的数字 II - 力扣(LeetCode)icon-default.png?t=N7T8https://leetcode.cn/problems/single-number-ii/solutions/746993/zhi-chu-xian-yi-ci-de-shu-zi-ii-by-leetc-23t6/

[LeetCode]Single Number, Single Number II & Single Number III - J坚持C - 博客园 (cnblogs.com)icon-default.png?t=N7T8https://www.cnblogs.com/wf751620780/p/10730758.html 

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

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

相关文章

在Vue项目中定义全局变量

在Vue项目中我们需要使用许多的变量来维护数据的流向和状态&#xff0c;这些变量可以是本地变量、组件变量、父子组件变量等&#xff0c;但这些变量都是有局限性的。在一些场景中&#xff0c;可能需要在多个组件中共享某个变量&#xff0c;此时全局变量就派上了用场。 定义全局…

NSSCTF第十页(2)

[HNCTF 2022 WEEK3]ssssti 题目提示是jinja2模板 怎么感觉之前做过&#xff0c;看到了注入 随便进行一下注入&#xff0c;发现了过滤 大致的黑名单 " _ args -- 无法使用 request.args os -- 无法导入os 不允许post -- 无法使用 request.value 正常用的payloa…

什么是协议栈? 用户态协议栈设计(udp协议栈)

什么是协议栈呢&#xff1f; &#xff08;协议栈&#xff08;Protocol Stack&#xff09;是计算机网络和通信系统中的一个重要概念&#xff0c;它指的是一组协议层的层次结构&#xff0c;这些协议层一起协同工作&#xff0c;以便在不同计算机或设备之间实现数据通信和交换。每…

暴力递归转动态规划(十三)

题目 给定3个参数&#xff0c;N&#xff0c;M&#xff0c;K 怪兽有N滴血&#xff0c;等着英雄来砍自己 英雄每一次打击&#xff0c;都会让怪兽流失[0~M]的血量 到底流失多少&#xff1f;每一次在[0~M]上等概率的获得一个值 求K次打击之后&#xff0c;英雄把怪兽砍死的概率。 暴…

httpclient工具类(支持泛型转换)

1、网上搜到的httpclient工具类的问题&#xff1a; 1.1、如下图我们都能够发现这种封装的问题&#xff1a; 代码繁杂、充斥了很多重复性代码返回值单一&#xff0c;无法拿到对应的Java Bean对象及List对象集合实际场景中会对接大量第三方的OPEN API&#xff0c;下述方法的扩展…

zookeeper集群搭建

zookeeper&#xff08;动物园管理员&#xff09;是一个广泛应用于分布式服务提供协调服务Apache的开源框架 Zookeeper从设计模式角度来理解&#xff1a;是一个基于观察者模式设计的分布式服务管理框架&#xff0c;它 负责存储和管理大家都关心的数据 &#xff0c;然 后 接受观察…

Java 正则表达式字母篇

字母 匹配 a-z 的小写字母 用 [a-z] 可以匹配一位 a-z 的小写字母&#xff0c; String regexaz "[a-z][z-z]";System.out.println("az".matches(regexaz));// trueSystem.out.println("aZ".matches(regexaz));// falseSystem.out.println(&qu…

第 04 章_逻辑架构

第 04 章_逻辑架构 1. 逻辑架构剖析 1. 1 服务器处理客户端请求 那服务器进程对客户端进程发送的请求做了什么处理&#xff0c;才能产生最后的处理结果呢&#xff1f;这里以查询请求为 例展示&#xff1a; 下面具体展开看一下&#xff1a; 1.2 Connectors 1.3 第 1 层&…

Docker网络模式_Docker常用命令_以及Docker如何给运行的镜像内容连接互联网_Docker网络模式原理---Docker工作笔记004

然后我们来看一下docker的网络模式: 这个docker我们先看一下电脑上的网络,有两个,1个是lo是测试用的一个是enp0s3这个是我们以太网地址,然后我们去: 安装docker 安装后我们再去ip address可以看到多出来一个网络是docker0 这里ip地址是172.17.0.1这个是私有地址外部无法访问 这…

TypeScript - 泛型 - 泛型方法中泛型的使用

对泛型的一个自我理解 泛型的使用&#xff0c;实际上就像一个占位符一样&#xff0c; 我先预定义一个类型&#xff0c;这个类型具体是啥只有在真正使用的时候才知道。从某种角度来看&#xff0c;泛型很像这个 any 类型啊。泛型的定义语法 泛型的定义使用 <T> 的方式来定…

VSCode实用远程主机功能

作为嵌入式开发者&#xff0c;经常在各种系统平台或者开发工具之间切换&#xff0c;比如你的代码在Linux虚拟机上&#xff0c;如果不习惯在Linux下用IDE&#xff0c;那么我尝试将Linux的目录通过samba共享出来&#xff0c;在windows下用网络映射盘的方式映射出来&#xff0c;VS…

Python某建筑平台数据, 实现网站JS逆向解密

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 环境使用: 首先我们先来安装一下写代码的软件&#xff08;对没安装的小白说&#xff09; Python 3.8 / 编译器 Pycharm 2021.2版本 / 编辑器 专业版是付费的 <文章下方名片可获取魔法永久用~> 社区版是免费的 模块…

Java Web 学习笔记(二) —— JDBC

目录 1 JDBC 概述2 JDBC 快速入门3 JDBC API 详解3.1 DriverManager3.2 Connection3.3 Statement3.4 ResultSet3.5 PreparedStatement3.5.1 代码模拟 SQL 注入3.5.2 PreparedStatement 的使用3.5.3 PreparedStatement 原理 4 数据库连接池4.1 数据库连接池概述4.2 数据库连接池…

佳易王配件进出库开单打印进销存管理系统软件下载

用版配件进出库开单打印系统&#xff0c;可以有效的管理&#xff1a;供货商信息&#xff0c;客户信息&#xff0c;进货入库打印&#xff0c;销售出库打印&#xff0c;进货明细或汇总统计查询&#xff0c;销售出库明细或汇总统计查询&#xff0c;库存查询&#xff0c;客户往来账…

集群调度-01

目录 1、调度约束 2、Pod 是 Kubernetes 的基础单元&#xff0c;Pod 启动典型创建过程如下 2.1 工作机制 **** 2.2 调度过程 *** 2.3 Predicate 有一系列的常见的算法可以使用&#xff1a; ** 2.4 指定调度节点 1、调度约束 Kubernetes 是通过 List-Watch **…

大型加油站3d全景虚拟现实展示平台实现全方位立体呈现

近年来&#xff0c;随着国民经济的快速发展&#xff0c;交通基础设施的不断改善&#xff0c;机动车保有量的持续飙升&#xff0c;以至于加油站的建设数量和密度也在不断扩张。加油站作为人流量大且常见的城市场景&#xff0c;对加油站进行安全防范措施具有非常重要的安全意义。…

NodeJS 安装及环境配置

下载地址&#xff1a;https://nodejs.org/zh-cn/download/ 安装 NodeJS 根据自己电脑系统及位数选择&#xff0c;一般都选择 windows 64位 .msi 格式安装包。 所用命令&#xff1a; node -v npm -v PS&#xff1a;如果以上两条命令都能执行成功&#xff0c;表示安装完成&#…

stable diffusion公司发布4款LLM大语言模型,为何大家都喜爱LLM?

stable diffusion模型是Stability AI开源的一个text-to-image的扩散模型&#xff0c;其模型在速度与质量上面有了质的突破&#xff0c;玩家们可以在自己消费级GPU上面来运行此模型&#xff0c;本模型基于CompVis 和 Runway 团队的Latent Diffusion Models。本期我们不介绍stabl…

Java自学第4课:Java数组,类,对象

1 一维数组的创建和使用 2种创建形式&#xff1a; &#xff08;1&#xff09;先声明&#xff0c;再用new分配内存 &#xff08;2&#xff09;声明的同时分配内存 2种幅值形式 &#xff08;1&#xff09;用new{}赋值 &#xff08;2&#xff09;用{}赋值 如果不使用的话&a…

apb介绍

https://www.cnblogs.com/xianyuIC/p/17279209.html***带testbench https://zhuanlan.zhihu.com/p/623829190?utm_id0 https://zhuanlan.zhihu.com/p/607964532带testbench by四人独行 https://blog.csdn.net/weixin_40377195/article/details/124899571 APB是最简单的AMBA总…