剑指offer 56:数组中只出现一次的两个数字

题目描述:

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

数据范围:数组长度2≤n≤1000,数组中每个数的大小0<val≤1000000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

提示:输出时按非降序排列。

示例1

输入:[1,4,1,6]

返回值:[4,6]

说明:返回的结果中较小的数排在前面

示例2

输入:[1,2,3,3,2,9]

返回值:[1,9]

解法一:map

思路:

1、遍历数组,找到每个元素的出现的次数,并保存在map中。

2、通过遍历map。找到出现次数是1的数字,作为结果返回。

代码:

import java.util.*;
public class Solution {
    public int[] FindNumsAppearOnce (int[] array) {
        Map<Integer, Integer> map = new HashMap<>();
        //遍历数组,通过map来存储每个元素出现的次数
        for(int i : array){
            //如果当前元素在map中已经存在,则出现次数加1;反之,则放入map
            if(map.containsKey(i)){
                map.put(i, map.get(i) + 1);
            }else{
                map.put(i, 1);
            }
        }
        //存储结果的数组
        int[] ret = new int[2];
        int index = 0;
        for(Integer key : map.keySet()){
            //如果元素出现次数是1.则存入结果数组
            if(map.get(key) == 1){
                ret[index++] = key;
            }
        }
        //返回结果
        return ret;
    }
}

解法二:位运算

思路:

定义一个变量,遍历数组进行异或运算,得到的值为这两个元素异或的结果。接着,提取出最右边的1,再次遍历数组,找到这个数,之后进行与运算就得到另一个数。以示例1为例:

代码:

import java.util.*;
public class Solution {
    public int[] FindNumsAppearOnce (int[] array) {
        //异或运算:任何数和0异或的结果都是它本身。
       int ret = 0;
        //遍历数组,得到出现次数为1的两个数的结果
       for(int i: array){
           ret ^= i;
       }
        //求一个不为0的数的最右边的1的写法
        int right = ret & (~ret + 1);
        //用来找到两个数中的一个
        int num1 = 0;
        //再次遍历
        for(int i : array){
            //如果某个数在这个位上是1,相与结果才是1
            if((i & right) == 0){
                num1 ^= i;
            }
        }
        int num2 = num1 ^ ret;
        int[] retArray = new int[2];
        retArray[0] = num1 < num2 ? num1 : num2;
        retArray[1] = num1 < num2 ? num2 : num1;
        //返回结果
        return retArray;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_47382783/article/details/121280606
今日推荐