剑指offer 40.数组中只出现一次的数字

 40.数组中只出现一次的数字

题目描述

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

思路一:

对数组排序,然后遍历数组,判断前后不相等的元素,第一个是num1[0], 第二个数num2[0], 注意如果前后相等的两个元素要跳过一位

 1 //num1,num2分别为长度为1的数组。传出参数
 2 //将num1[0],num2[0]设置为返回结果
 3 import java.util.Arrays;
 4 public class Solution {
 5     public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
 6         // 排序
 7         Arrays.sort(array);
 8         
 9         // 然后遍历数组,判断前后不相等的元素
10         boolean flag = true;    // 判断是第一个满足要求的数字
11         for(int i = 0; i < array.length; i++){
12             if(i + 1 < array.length && array[i] == array[i + 1]){
13                 i++;    // 跳过下一个数
14             }else {
15                 if(flag){
16                     num1[0] = array[i];
17                     flag = false;
18                 }else{
19                     num2[0] = array[i];
20                 }
21             }
22         }
23     }
24 }

 

思路二:

利用异或运算

异或运算的规则是:两个相同数字异或=0一个数和0异或还是它本身

只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。所以我们尝试把原数组分成两个数组,每个数组分别含有一个只出现一次的数字,且每个数组中其他元素均是成对出现的。

分成这样两个数组的过程是:假设 两个只出现一次的数字分别为 A 和 B

1. 定义一个变量 xor ,遍历数组,让这个变量与每个元素都进行一次异或运算,最终的结果肯定是 A 与 B 做异或的结果,因为其他元素都成对出现抵消为0 了。

2. 从低位开始,找到 xor 的二进制表示中第一个1 出现的位置, 假设位置为 p ,按照异或的规则,这个位置的值既然 是 1,那么说明 A 和 B两个元素在该位置的值肯定不同,肯定是一个是0,一个是1

3. 定义一个变量 index ,初值为 1, 让它左移 p 位,这样 index 的二进制表示中只有 p 位 为 1, 其他位均为0, 让 index 分别与元素组中每个元素进行按位与运算,判断是否为 0,如果为0则将这个元素归入到数组1, 否则归入到数组2,这样每个数组都有一个只出现一次的元素,而且每个数组中除了这个元素外其他元素肯定都是成对出现的。

4. 让num1[0] 对数组1的每个元素分别做异或运算,最终 num1[0] 中的元素肯定就等于 A 或 B 中的一个;同理,让num2[0] 对数组2中的每个元素分别做异或运算,最终num2[0] 中的值肯定是 A 或 B 中剩下的那个。

这里做了一个小优化:把步骤 4 和 步骤 3合并,两个操作同时进行,也就是在 让 index 与原数组中元素进行按位与运算后不将数存入数组1或者数组 2,而是直接让 num1[0] 或 num2[0] 与该数做异或运算,这样最后num1[0] 和 num2[0]就能分别存储 A 或 B 中的一个。

 1 //num1,num2分别为长度为1的数组。传出参数
 2 //将num1[0],num2[0]设置为返回结果
 3 import java.util.Arrays;
 4 public class Solution {
 5     public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
 6        int xor = 0;
 7         for(int i = 0; i < array.length;i++){
 8             xor ^= array[i];
 9         }
10         // 求出第一个 1 的位置
11         int index = 1;
12         while((index & xor) == 0)
13             index <<= 1;
14         // 3/4.
15         for(int i = 0; i < array.length; i++){
16             if((index & array[i]) != 0)
17                 num1[0] ^= array[i];
18             else
19                 num2[0] ^= array[i];
20         }
21         
22     }
23 }

 

posted @ 2020-03-30 21:37  Lucky小黄人^_^  阅读(127)  评论(0编辑  收藏  举报