news 2026/7/5 3:13:38

key 为出现的数字, value 为该数字出现的次数。遍历⾥⾯所有的数字,如果 hashmap 中存在,那么 value (次数)+1,如果 hashmap 中不存在,那么 value 置为1。

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
key 为出现的数字, value 为该数字出现的次数。遍历⾥⾯所有的数字,如果 hashmap 中存在,那么 value (次数)+1,如果 hashmap 中不存在,那么 value 置为1。

遍历完成之后,需要将次数为 1 的数字捞出来,同样是遍历 hashmap ,由于只有两个满⾜条件,我们设置⼀个标识变量,初始化为1,如果找到第⼀个满⾜条件的数字,除了写⼊放回数组中,还需要将该标识置为 2 ,表示接下来找的是第 2 个。

如果找到第 2 个,那么写⼊之后,直接 return 。

java

public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { Map<Integer, Integer> maps = new HashMap<>(); if (array != null) { for (int n : array) { Integer num = maps.get(n); if (num == null) { // map中不存在 maps.put(n, 1); } else { // map中已经存在 maps.put(n, num + 1); } } } int index = 1; for (Map.Entry<Integer, Integer> entry : maps.entrySet()) { if (entry.getValue() == 1) { if (index == 1) { num1[0] = entry.getKey(); index++; } else { num2[0] = entry.getKey(); return; } } } }
  • 时间复杂度:O(n),需要遍历数组两次
  • 空间复杂度:O(n),需要HashMap存储频率信息

排序遍历

先对数组排序,然后遍历查找不连续的数字。排序后相同的数字会相邻,遍历找到不连续的数字

java

public class Solution { public int[] FindNumsAppearOnce(int[] nums) { if (nums == null || nums.length < 2) { return new int[0]; } // 对数组进行排序 int[] sorted = nums.clone(); Arrays.sort(sorted); int[] result = new int[2]; int index = 0; // 遍历查找不连续的数字 for (int i = 0; i < sorted.length; i++) { // 检查当前数字是否与前后都不同 boolean isSingle = true; // 检查前一个元素(如果不是第一个元素) if (i > 0 && sorted[i] == sorted[i - 1]) { isSingle = false; } // 检查后一个元素(如果不是最后一个元素) if (i < sorted.length - 1 && sorted[i] == sorted[i + 1]) { isSingle = false; } if (isSingle) { result[index++] = sorted[i]; if (index == 2) break; // 找到两个数字后退出 } } // 确保结果按升序排列 if (result[0] > result[1]) { int temp = result[0]; result[0] = result[1]; result[1] = temp; } return result; } }
  • 时间复杂度:O(nlogn),主要来自排序操作
  • 空间复杂度:O(1) 或 O(n),取决于是否克隆数组

位运算(最优解)

⾸先需要了解⼀定位运算知识,异或是指⼆进制中,⼀个位上的数如果相同结果就是0,不同则结果是0.

也就是如果⼀个数的最低位是0,另⼀个数的最低位是0,那么异或结果的最低位是0;如果⼀个数的最低位是0,另⼀个数的最低位是1,那么异或结果的最低位是1。

异或操作可以交换,不影响结果:ABC = ABC

A^A=0,任何⼀个数异或⾃身,等于0,因为所有位都相同

A^0 = A,任何⼀个数异或0,等于⾃身,因为所有位如果和0不同,就是1,也就是保留了⾃身的数值

假设⾥⾯出现⼀次的两个元素为 A 和 B ,初始化异或结果 res 为0,遍历数组⾥⾯所有的数,都进⾏异或操作,则最后结果 res = A^B 。

但是我们拿到这个 A 和 B 异或之后的结果,怎么区分呢?

有⼀种巧妙的思路,因为 A 和 B 的某⼀位不同才会在结果中出现 1 ,说明在那⼀位上, A 和 B 中肯定有⼀个是 0 ,有⼀个是 1 。

那我们取出异或结果 res 最低位的1,假设这个数值是 temp (temp只有⼀个位是1,也就是A和B最后不同的位)

遍历数组中的元素,和 temp 进⾏与操作,如果和 temp 相与,不等于0。说明这个元素的该位上也是1。那就说明它很有可能就是 A 和 B 中的⼀个。

只是有可能,其他的数也有可能该位上为 1 。但是符合这种情况的,其他数肯定出现两次,⽽ A 和 B只可能有⼀个符合,并且只有可能出现⼀次 A 或者 B 。

凡是符合和 temp 相与,结果不为0的,我们进⾏异或操作。

也就是可能出现, res1 = BCDCD...EE^B 或者 res1 = ACDCD...EE 。

上⾯的式⼦可以视为 res1 = B 或者 res1 = A

这样操作下来,我们就知道了 res1 肯定是其中⼀个只出现⼀次的数( A 或者 B ),⽽同时上⾯计算出了 res = A^B ,也就是可以通过 res1^res 求出另⼀个数。

java

public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) { // A和B异或的结果 int res = 0; for (int val : array) { res ^= val; } // temp保存了两个数最后⼀个不同的位 int temp = res & (-res); // 保存和最后⼀个不同的位异或的结果 int res1 = 0; for (int val : array) { // 不等于0说明可能是其中⼀个数,⾄少排除了另外⼀个数 if ((temp & val) != 0) { res1 ^= val; } } // 由于其他满⾜条件的数字都出现两次,所以结果肯定就是只出现⼀次的数 num1[0] = res1; // 求出另外⼀个数 num2[0] = res ^ res1; }
  • 时间复杂度:O(n),只需要遍历数组两次
  • 空间复杂度:O(1),只使用固定数量的变量
位运算原理解析

通过示例详细解释算法过程:

输入[92,3,43,54,92,43,2,2,54,1]
单次数:3 和 1

步骤1:计算所有数字的异或结果

java

92 ^ 3 ^ 43 ^ 54 ^ 92 ^ 43 ^ 2 ^ 2 ^ 54 ^ 1 = (92 ^ 92) ^ (43 ^ 43) ^ (2 ^ 2) ^ (54 ^ 54) ^ 3 ^ 1 = 0 ^ 0 ^ 0 ^ 0 ^ (3 ^ 1) = 3 ^ 1 = 2

步骤2:找到异或结果的最低位的1

java

3的二进制: 0011 1的二进制: 0001 3^1=2的二进制: 0010 最低位的1在从右往左第2位(值为2)

步骤3:根据最低位1分组

  • 第1组(第2位为0):3(0011), 43(101011), 54(110110), 1(0001), 92(1011100)
  • 第2组(第2位为1):2(0010)

步骤4:分别异或各组

java

第1组: 3 ^ 43 ^ 54 ^ 1 ^ 92 ^ 43 ^ 54 ^ 92 = (3 ^ 1) ^ (43 ^ 43) ^ (54 ^ 54) ^ (92 ^ 92) = 3 ^ 1 = 2 ❌ 这里应该是 3 ^ 1 = 2,但我们需要重新计算正确的分组 让我们重新正确分组计算: 实际分组应该是: 第1组(第2位为0):3, 1 // 只有这两个数在第2位为0且是单次数 第2组(第2位为1):所有其他数 正确的计算: 第1组: 3 ^ 1 = 2 第2组: 92 ^ 43 ^ 54 ^ 92 ^ 43 ^ 2 ^ 2 ^ 54 = 0
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/5 3:14:43

.算数操作符

移位操作符 使用条件&#xff1a;只能对于 int类型 使用&#xff0c;无符号整型这里算作正数。移位操作符移动的位数不能为负数&#xff0c;标准未定义这种写法&#xff0c;所以在不同编译器中有不同结果 a.<< 左移 对整数的补码左移一位 左边丢弃&#xff0c;右边补零…

作者头像 李华
网站建设 2026/7/4 13:16:55

AI编程Token成本将与开发者薪资持平,企业如何应对?

企业很快就可能在开发者AI Token使用上的支出&#xff0c;与支付给他们的薪资不相上下。根据Gartner的研究&#xff0c;这一成本将在未来两年内达到甚至超过软件工程师的月均薪资水平。这一趋势的形成&#xff0c;不仅因为开发者正越来越多地采用生成式AI与智能体工具&#xff…

作者头像 李华
网站建设 2026/7/4 3:12:45

ESP32 + 传感器:手把手教你做土壤监测终端

ESP32 传感器&#xff1a;手把手教你做土壤监测终端上一篇给了硬件清单&#xff0c;这篇直接上代码。从 GPIO 初始化到传感器读数&#xff0c;再到 MQTT 上发&#xff0c;最后低功耗优化——每一行都有注释&#xff0c;复制到 Arduino IDE 里就能跑。前置准备 软件环境&#x…

作者头像 李华
网站建设 2026/7/4 2:14:42

微信小程序:农户手机上的「农场管家」

微信小程序&#xff1a;农户手机上的「农场管家」平台搭好了&#xff0c;但农户不可能打开电脑看数据。他们需要手机上扫一下就能看到大棚温湿度、点一下就能远程开水泵。这篇用 UniApp&#xff08;Vue 3&#xff09;开发一个小程序&#xff1a;实时数据、远程控制、告警推送、…

作者头像 李华
网站建设 2026/7/4 3:21:14

自动灌溉系统:AI 什么时候浇水,比老农还准?

自动灌溉系统&#xff1a;AI 什么时候浇水&#xff0c;比老农还准&#xff1f;灌溉是农业最高频的操作&#xff0c;也是浪费最严重的环节。老农的经验是「看着土干了就浇」&#xff0c;一浇就是大水漫灌&#xff0c;蒸发掉的比渗进土里的多。这篇从简单的定时/阈值出发&#xf…

作者头像 李华