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

news2024/11/17 15:39:36

给你一个整数数组 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) // 所以,先计算出b

a = (~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.coloradmin.cn/o/1155912.html

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

相关文章

运行项目报错error in ./node_modules/marked/lib/marked.umd.js

今天跑项目时发现一个报错&#xff0c;问题出在marked这个包&#xff0c;然后翻看package.json里面也没有这个包&#xff0c;全局搜索项目也没有这个包相关的信息&#xff0c;可它就是报错&#xff0c;索性直接把它给卸载发现还是报错 报错原因&#xff1a;包的版本太高 解决…

AI:47-基于深度学习的人像背景替换研究

🚀 本文选自专栏:AI领域专栏 从基础到实践,深入了解算法、案例和最新趋势。无论你是初学者还是经验丰富的数据科学家,通过案例和项目实践,掌握核心概念和实用技能。每篇案例都包含代码实例,详细讲解供大家学习。 📌📌📌本专栏包含以下学习方向: 机器学习、深度学…

「完美修复」concrt140.dll丢失的修复方法

concrt140.dll是一个动态链接库文件&#xff0c;它是Microsoft Visual C 2015 Redistributable的一部分。这个文件通常位于Windows系统的System32文件夹中&#xff0c;它提供了一些用于多线程编程的函数和类。当你在运行某些程序时&#xff0c;系统会调用这个文件中的函数来执行…

系列三十五、Spring AOP失效原因以及解决方式

一、Spring AOP失效原因 &#xff08;1&#xff09;内部调用不会触发AOP&#xff1b; &#xff08;2&#xff09;方法是private修饰的&#xff0c;AOP会失效&#xff1b; 解决方法&#xff1a;改成public &#xff08;3&#xff09;目标类没有配置为bean&#xf…

【P2P owt】owt-client-native-p2p-e2e-test vs2017构建7:依赖库及路径

依赖库 G:\CDN\LiveServiceMesh\cdnsignal\third_party\libeva\thirdparty\janbar-openssl\out32\ssl\Debug\libssl-

vue面试题-原理层

虚拟dom 虚拟dom是什么?虚拟dom在vue中做了什么? vue 渲染两条线 虚拟dom是如何提升vue的渲染效率的? 局部更新节点数据将直接操作dom的地方拿到两个js对象之中去做比较 虚拟dom生成三要素 节点类型/目标元素 [必须有]节点属性子节点 Diff中的patch 虚拟dom 虚拟dom是什么…

编写Groovy Hello World 程序

使用 IntelliJ IDEA 打开 IntelliJ IDEA&#xff0c;并创建一个新的 Groovy 项目。 在项目中创建一个新的 Groovy 类文件&#xff0c;命名为 HelloWorld.groovy。 在 HelloWorld.groovy 文件中&#xff0c;编写以下代码&#xff1a; class HelloWorld {static void main(Stri…

初识Java 16-3 字符串

目录 扫描输入&#xff08;Scanner&#xff09; Scanner的分隔符 使用正则表达式扫描 StringTokenizer 本笔记参考自&#xff1a; 《On Java 中文版》 扫描输入&#xff08;Scanner&#xff09; 先看看在Scanner类加入之前&#xff0c;Java是如何处理文件或标准输入的&…

国际物流常见风险如何规避_箱讯科技

外贸物流是国际贸易的重要环节&#xff0c;其管理和效率的高低直接影响着贸易的成本和效益。因此&#xff0c;外贸企业应该重视物流的组织和管理&#xff0c;提高物流运作的效率。 国际物流基础知识 01什么是“双清包税”和“双清不包税” 双清包税上门又叫双清包税到门&…

接口测试学习手册

很多人会谈论接口测试。到底什么是接口测试&#xff1f;如何进行接口测试&#xff1f;这篇文章会帮到你。 前端和后端 在谈论接口测试之前&#xff0c;让我们先明确前端和后端这两个概念。 前端是我们在网页或移动应用程序中看到的页面&#xff0c;它由 HTML 和 CSS 编写而成…

天软特色因子看板(2023.10 第13期)

该因子看板跟踪天软特色因子A05005(近一月单笔流涌金额占比(%)&#xff0c;该因子为近一个月单笔流通金额占比因&#xff0c;用以刻画股票在收盘时&#xff0c;主力资金在总交易金额中所占的比重。 今日为该因子跟踪第11期&#xff0c;跟踪其在SW801150 (申万医药生物) 中的表现…

STM32-RTC实时时钟

RTC实时时钟 STM32的RTC外设&#xff0c;实质上是一个掉电后还继续运行的定时器。类似于通用定时器TIM外设&#xff0c;可以计时和触发中断。 掉电指的是电源VDD断开时为了RTC外设掉电继续运行&#xff0c;必须接上锂电池给STM32的RTC、备份发卡通过Vbat引脚供电。当主电源VDD有…

TensorBoard官方教程

如何在 PYTORCH 中使用 TENSORBOARD&#xff1a;https://pytorch.org/tutorials/recipes/recipes/tensorboard_with_pytorch.html 更详细一点的&#xff1a;https://pytorch.org/docs/stable/tensorboard.html 主要是 一个函数 writer.add_scalar()

JavaScript基础知识19——循环结构:while循环

哈喽&#xff0c;你好&#xff0c;我是雷工。 本节学习JavaScript基础语法的循环结构&#xff1a;while循环&#xff0c;以下为学习笔记。 while循环 循环概念&#xff1a;重复执行一些操作&#xff1b; 循环特征&#xff1a;不断地重复&#xff1b; while&#xff1a;在…期间…

echarts 力向导图_关系图_知识图谱

Echarts 常用各类图表模板配置 注意&#xff1a; 这里主要就是基于各类图表&#xff0c;更多的使用 Echarts 的各类配置项&#xff1b; 以下代码都可以复制到 Echarts 官网&#xff0c;直接预览&#xff1b; 图标模板目录 Echarts 常用各类图表模板配置一、力向导图二、环形图…

VS Code开发Java之快速入门

VS Code 开发Java的环境 要在VS Code中开发Java应用程序&#xff0c;需要安装以下组件&#xff1a; Java Development Kit&#xff08;JDK&#xff09;&#xff1a;JDK是Java开发的基础&#xff0c;需要下载和安装JDK。Visual Studio Code&#xff1a;VS Code是一个免费的跨平…

Freertos tick 不响应中断的解决方法

代码环境 babyosfreertos 操作方法 通过 shell 操作eeprom 的写操作 问题现象 整个系统会卡在延时函数这里&#xff0c;卡的原因是rtos 的tick中断不响应了。 shell不响应外部命令 系统是正常运行的。 解决方法 成功的方法 ms延时由依赖tick改为us的堵塞延时&#xff1…

虚拟化的基础知识

目录 虚拟化基础 虚拟化的概念 虚拟化的特征&#xff08;本质&#xff09; 虚拟机的两大派别 VMM讲解 虚拟化中的一些重要概念 VMM的功能以及分类 虚拟化的架构 寄居虚拟化 裸金属虚拟化 操作系统虚拟化 混合虚拟化 虚拟化的三个方向 虚拟化基础 虚拟化的概念 什…

VMware打开centos黑屏解决方法汇总

VMware打开centos黑屏解决方法汇总 前言&#xff1a;一. VMware打开centos黑屏解决方法汇总一 .情况情况一&#xff1a;情况二情况三 二. 解决方法最简单的方法&#xff1a;一. 以管理员权限在命令行执行1. 管理员身份运行cmd2. 输入“netsh winsock reset”,回车3. 重启电脑即…

世界电信日 | 人大金仓助力中国移动租赁核算系统升级上线

世界电信日 5月17日恰逢第五十四个世界电信日&#xff0c;运营商作为新型基础设施建设以及维护网信安全的主力军&#xff0c;掌握关键核心技术&#xff0c;实现科技自立自强刻不容缓。 作为数据库领域国家队&#xff0c;人大金仓坚持原始创新&#xff0c;低难度、低成本、低风…