面试题56 - I. 数组中数字出现的次数

本文介绍了一种在O(n)时间复杂度和O(1)空间复杂度下找出数组中仅出现一次的两个数字的算法。通过异或运算和逻辑与操作,巧妙地分离出这两数,附带示例代码验证算法正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

示例 2:
输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

题目分析:

在这里插入图片描述

Java代码:
import java.util.Arrays;
/**
 * 面试题56 - I. 数组中数字出现的次数
 * 一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。
 * 要求时间复杂度是O(n),空间复杂度是O(1)。
 *
 * 示例 1:
 * 输入:nums = [4,1,4,6]
 * 输出:[1,6] 或 [6,1]
 *
 * 示例 2:
 * 输入:nums = [1,2,10,4,1,4,3,3]
 * 输出:[2,10] 或 [10,2]
 */
public class Offer56_I {

    public static int[] singleNumbers(int[] nums) {
        // 遍历数组中所有元素,进行异或,得到单独出现一次的两个数据的异或值。
        int xor = 0;
        for (int t: nums) {
            xor ^= t;
        }
        // 获取到异或值的最低位的1所表示的数值。
        //  n&-n是求一个二进制数的最低位的1对应的数。 !!!
        int flag = xor & (-xor);
        // 该位的异或值为1,说明肯定一方为0,一方为1,因此可以通过逻辑与操作,将这两个数区分。
        int ans1 = 0;
        int ans2 = 0;
        for (int temp:nums) {
            // 逻辑与操作仅有两种结果,要么等于0,要么等于flag本身
            if ((temp&flag)==0){
                ans1 ^= temp;
            }else {
                ans2 ^= temp;
            }
        }
        return new int[]{ans1, ans2};
    }

    public static void main(String[] args) {
        int[] nums1 = {0,3,10,4,0,4,3,6,7,7,43,34,43,34,6,9};   // 10,9
        int[] nums2 = {1,1,8,8,4,4,6,6,7,7,3,15};   // 3,15
        int[] nums3 = {9,9,8,8,0,0,1,1,6,6,4,3};    // 4,3
        int[] nums4 = {88,77,11,33,55,11,55,96,69,96,69,24, 88, 77};    // 33  24
        int[] nums5 = {84,48,84,48,75,59,95,59};    // 75,95

        System.out.println(Arrays.toString(singleNumbers(nums1)));
        System.out.println(Arrays.toString(singleNumbers(nums2)));
        System.out.println(Arrays.toString(singleNumbers(nums3)));
        System.out.println(Arrays.toString(singleNumbers(nums4)));
        System.out.println(Arrays.toString(singleNumbers(nums5)));
    }
}

【注】
(1):leetcode 等平台只要我们完成一个函数即可,本人初出茅庐,为了巩固基本知识,故自己补充了部分代码,用于练手。本代码也许存在漏洞,望高手赐教。感谢!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值