剑指offer系列之三十九:数组中只出现一次的数字

题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

先考虑只有只有一个数字出现一次的情况,因为其他数字只出现了两次,所以对这两个数字进行异或运算的时候,其结果是0,那么那个只出现一次的数字进行异或运算的时候,其结果必然不是0,所以可以利用这点找出那个只出现一次的数字。现在考虑有两个数字出现一次的情况,仍然借鉴上面的思路,因为只出现一次的那个数字的异或结果不是0,遍历整个数组进行异或运算的结果也肯定不是0,现在可以对该数右边第一个是1的位的位置作为标准(记为n),将整个数组进行拆分,这样会得到两组数组,一组n位的位置的值都是1,两组则都是0。用一个简单的例子就可以说明这点:一个数组{1,2,2,3,3,4},遍历进行异或运算的结果是0110,右边第一个不是0的位的位置的2,那么数组{1}和{2,2,3,3,4}。第一个数组的右数第2位的值都是0,而第二个数组右数第2位的值都是0。所以在对第一组进行异或运算的结果是1,第二个数组进行异或运算的结果是4,因为其他都出现了两次,异或运算之后变成了0。

根据上述思路,实现的代码如下(已被牛客AC):

package com.rhwayfun.offer;

public class FindNumberAppearOnce {

    public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) {
        if(array == null || array.length < 2) return;
        int resultExclusiveOr = 0;
        for (int i = 0; i < array.length; i++) {
            resultExclusiveOr ^= array[i];
        }
        //找到右边第一个是1的位的位置
        int rightFirstIndexIs1 = findFirstIndexis1(resultExclusiveOr);
        //把该位是1的与不是1的数分别两部分
        for (int i = 0; i < array.length; i++) {
            if(isBit1(array[i],rightFirstIndexIs1)){
                num1[0] ^= array[i];
            }else{
                num2[0] ^= array[i];
            }
        }
    }

    //数num右数index为是否为1
    private boolean isBit1(int num, int index) {
        num = num >> index;
        return ((num & 1) == 1) ? true : false;
    }

    //找到右边第一个是1位的位置
    private int findFirstIndexis1(int resultExclusiveOr) {
        int index = 0;
        while(((resultExclusiveOr & 1) == 0) && index < 32){
            resultExclusiveOr = resultExclusiveOr >> 1;
            index++;
        }
        return index;
    }

    public static void main(String[] args) {
        int[] array = new int[]{2,4,3,6,3,2,5,5};
        int[] num1 = new int[]{0};
        int[] num2 = new int[]{0};
        new FindNumberAppearOnce().FindNumsAppearOnce(array, num1, num2);
        System.out.println(num1[0] + "," + num2[0]);
    }
}
时间: 2025-01-02 13:11:10

剑指offer系列之三十九:数组中只出现一次的数字的相关文章

剑指offer系列之三十:整数中1出现的次数

题目描述 求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了.ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数. 有一种比较简洁的思路:由于是一个整数区间,所以可以对每一个数进行判断,那么如何判断某个数中1出现了多少次呢?注意到如果一个数一直被10除,如果被10整除后的余数是1,那么一定出现了数字1.举个例子,数字11

剑指offer系列之三十六:数字在排序数组中出现的次数

题目描述 统计一个数字在排序数组中出现的次数. 因为是排序数组,自然联想到二分查找算法,这样我们在二分的时候可能会获取多个相同的数字.就是说,中间那个位置的值可能刚好是统计的那个值,假设为k.那么k还有可能在前面或者后面出现,在这个基础上继续二分当然也是可以的,如果能够在使用二分查找算法的时候统计出第一个k和最后一个k出现的位置,那么k出现的次数自然就确定了.第一个k出现的位置,可以使用二分查找算法,如果中间位置的值刚好是k,那么继续比较中间位置前面位置的值是不是也是k,如果不是那么该中间位置就

剑指offer系列之三十四:数组中的逆序对

题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数. 要找到数组中的逆序对,一种思路是每遍历到一个元素的时候就和后面的元素进行一一比较,这种算法的时间复杂度是O(n2),所以不是很理想.我们可以借鉴归并排序的思想,把数组划分为子数组,然后对每个子数组中的逆序对数进行统计,统计完成后再并到一个新的数组中进行统计,这样就化整为零,实现了高效统计.总计起来思路就是:首先把数组划分为子数组,然后统计子数组中的逆序对数,然后

剑指offer系列之四十九:数组中重复的数字

题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是重复的数字2或者3. 此题的思路还是比较简单的,与之前找出只出现一次的数字的题目有些类似,基本思路还是创建一个Map容器,key是出现的数字,value则是该数字出现的次数.在遍历数组的过程中,只要容器中已经出现了该数字,那么就直接返回给数组,

剑指offer系列之十九:包含min函数的栈

题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数.要求时间复杂度是O(1). 还是先说一下思路吧,因为每次方元素进栈的时候不能保证栈顶元素都是最小的,所以需要想办法使得栈顶元素始终是最小的元素,排序是一种思路,但是每次排序还设计重新出栈和入栈,想来应该不是这样的.一种思路是可以利用一个辅助栈,相当于是以空间换时间了.具体思路是:当入栈的新元素原先栈顶元素小的话就该元素放入一个辅助栈中,如果新入栈的元素比原先栈顶元素大,则在辅助栈中继续放原先最小的元素.这样一直放下去

剑指offer系列之三十八:判断是否是平衡二叉树

题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 所谓平衡二叉树就对某个结点来讲,其左子树的深度与右子树深度的绝对值不超过1.由于需要对每个节点进行判断,所以可以采用递归的思路进行解决.具体思路是:先求出根节点的左右子树的深度,并对两者进行判断,如果没有满足左右子树的深度的绝对值不超过1的条件,那么就不是平衡二叉树.下一步,自然就是分别对根节点的左右子树进行递归判断了,这样一直到叶子结点.整棵二叉树的所有节点都判断完毕,所以这个问题就解决了.下面是这种思路的实现代码(已被牛客AC): p

剑指offer系列之三十五:两个链表的第一个公共节点

题目描述 输入两个链表,找出它们的第一个公共结点. 由于是单链表,所以可以发现从第一个公共节点开始,后面的结点都是相同的,一种思路是从两个链表的尾部开始遍历,直到发现最后一个相同的结点为止,那么这最后一个相同的结点是单链表的角度看就是两个链表的第一个公共节点了.还有一种思路是不需要从尾部开始遍历,毕竟从尾部遍历单链表的话还得使用反转链表的方法进行操作,首先计算出两个链表的长度,让更长的那个单链表先移动两个链表长度差值个位置,然后两个链表同时移动,从更短的那个链表的第一个位置开始遍历,两个链表都往

剑指offer系列之五十九:链表中环的入口节点

题目描述 一个链表中包含环,请找出该链表的环的入口结点. 此题的思路其实 很简单,之所以出现环,是因为在整个链表中出现了重复的节点,而遇到的第一个重复的节点就是环的入口节点.所以可以使用Set来保存遍历到的节点,因为Set集合是不允许出现重复元素的,所以当一个节点被第二次添加的时候,往Set中放元素是失败的.所以可以利用这一点找出第一个重复的元素.基于这种思路的代码比较简洁,代码如下(已被牛客AC): import java.util.HashSet; import java.util.Set;

剑指offer系列之三十二:寻找丑数

题目描述 把只包含因子2.3和5的数称作丑数(Ugly Number).例如6.8都是丑数,但14不是,因为它包含因子7. 习惯上我们把1当做是第一个丑数.求按从小到大的顺序的第N个丑数. 因为丑数只有2.3和5这三个因子,那么如果一个是丑数的话,一定是可以被这个三个因子整除的,所以我们可以通过把一个数一直被三个因子除,这样最后如果该数变成1的话(因为第一个丑数是1),那么就验证了该数就是丑数.那么如果想找出第k个丑数的话,就可以从第一个数开始循环,对每一个数进行丑数的判断,从而找到符合要求的第