欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

数组中只出现1次的两个数

程序员文章站 2024-03-15 09:26:35
...

数组中只出现1次的两个数

思路

首先我们可以考虑下这个题目的简化版——数组中除一个数字只出现1次外,其它数字都成对出现,要求尽快找出这个数字。根据异或运算的特点,直接异或一次就可以找出这个数字。

现在数组中有两个数字只出现1次,直接异或一次只能得到这两个数字的异或结果,但光从这个结果肯定无法得到这个两个数字。因此我们来分析下简化版中“异或”解法的关键点,这个关键点也相当明显——数组只能有一个数字出现1次。

设题目中这两个只出现1次的数字分别为A和B,如果能将A,B分开到二个数组中,那显然符合“异或”解法的关键点了。因此这个题目的关键点就是将A,B分开到二个数组中。由于A,B肯定是不相等的,因此在二进制上必定有一位是不同的。根据这一位是0还是1可以将A,B分开到A组和B组。而这个数组中其它数字要么就属于A组,要么就属于B组。再对A组和B组分别执行“异或”解法就可以得到A,B了。而要判断A,B在哪一位上不相同,只要根据A异或B的结果就可以知道了,这个结果在二进制上为1的位都说明A,B在这一位上是不相同的。
数组中只出现1次的两个数

所有元素异或后,在找出最右边为1的时,主要利用正数原码和其对应相反数补码的关系:

对于一个数字x,x&(-x)之后得到的数字,是把x中最右边的1保留下来,其他位全部为0。注意,这里的-x是x的相反数。

package com.zhumq.leetcode;

import java.util.Arrays;

import org.junit.Test;

public class FindTwoNumsAppearOnce {
    /*
     * 返回一个数最低位的1,其他的各位都为0,利用补码和原码的关系
     */
    public int FindFirstBit1(int num) {
        return num&(-num);
    }

    /**
     * 根据res判断n的特定位是否为1
     * @param n 
     * @param res res中只有一位为1,是前面FirstBit1的返回值
     * @return
     */
    public boolean IsBit1(int n,int res) {
        return ((n&res)==0) ? false:true;
    }


    public int[] FindNumsAppearOnce(int arr[])
    {
        //数组为空或者元素个数下于2时返回null
        if(arr==null || arr.length<2)
            return null;

        //全部异或之后的值,即A,B异或后的值
        int allXor = 0;
        //全部异或,allXor保存异或的结果
        for(int i=0;i<arr.length;i++)
            allXor ^= arr[i];
        //最低位的1
        int res = FindFirstBit1(allXor);

        int num1 =0, num2 = 0;
        for(int i=0;i<arr.length;i++)
        {   
            /*
             * 根据最低位是否为1来划分异或
             *      相同的数字相同的位上的值是相同的,要么都为1,要么都为0,
             *      因此同样可以通过判断该位是否为1来将这些出现两次的数字划分到同一个子数组中,
             *      该位如果为1,就分到一个子数组中,如果为0,就分到另一个子数组中。
             *      不管划分的是否均匀,只要保证来个相同的元素分到同一边即可,即使两两相同的元素全分到同一边异或后结果也还是一样。
             */
            if(IsBit1(arr[i],res))
                num1 ^= arr[i];
            else
                num2 ^= arr[i];
        }
        return new int[] {num1,num2};
    }
    @Test
    public void test1() {
        int arr[] = {1,2,3,3,1,4,5,4,5,6};
        System.out.println(Arrays.toString(FindNumsAppearOnce(arr)));
    }
}

上一篇: BERT论文笔记

下一篇: ZFNet论文笔记