[剣はオファーを指します] 56。数字が配列に現れる回数

タイトル説明

ここに画像の説明を挿入します
ここに画像の説明を挿入します

// 56. 数组中数字出现的次数


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


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


回答

セット支援ソリューション

 集合辅助 

// 第一时间能想到的简单方法,好理解但不是最优


// 力扣
// 定义一个集合set,遍历nums中的所有元素nums[i],并将nums[i]存入set中
// 如果存不进,说明nums[i]出现了2次,在set中删除nums[i],留下来的就
// 都是只出现过一次的元素了,提取出来存入数组res中,返回即可。
// 执行用时:13 ms, 在所有 Java 提交中击败了10.23%的用户
// 内存消耗:39.7 MB, 在所有 Java 提交中击败了97.13%的用户
import java.util.HashSet;
class Solution {
    public int[] singleNumbers(int[] nums) {
		HashSet<Integer> set = new HashSet<Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (!set.add(nums[i]))
                set.remove(nums[i]);
        }
        int[] res = new int[set.size()];
        int i = 0;
        for (int num: set) {
            res[i++] = num;
        }
        return res;
    }
}

// 牛客
// 运行时间:11ms,超过59.56%用Java提交的代码
// 占用内存:11092KB,超过51.92%用Java提交的代码

import java.util.*;
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 
     * @return int整型一维数组
     */
    public int[] FindNumsAppearOnce (int[] array) {
		HashSet<Integer> set = new HashSet<Integer>();
        for (int i = 0; i < array.length; i++) {
            if (!set.add(array[i]))
                set.remove(array[i]);
        }
        int[] res = new int[set.size()];
        int i = 0;
        for (int num: set) {
            res[i++] = num;
        }
        return res;
    }
}

最適なソリューション

/// 位运算法 /

// 位运算法才是真正要学的最优解法
// 首先需要说明,异或操作 ^ 的性质包括:
// 交换律
// 结合律
// A ^ 0 = A; 
// A ^ A = 0

// 问题一:
// 假设nums只存在1个只出现过1次的数字,为A,其他数字都出现了2次
// 且nums数组为{10, 10, A, 2, 5, 5, 2},那么我们把数字全部异或起来
// 就可以把A分离出来,
// 即 10^10^A^2^5^5^2 = 10^10^2^2^5^5^A (交换律) = 0^0^0^A = A
// 如果把题目换成这样,本题就做完了,可惜换不得。
// 
// 问题二:
// 题目中,数组nums存在2个只出现1次的数字,假设为A,B。
// 其他数字都出现了两次,我们假设nums数组为{10, 10, A, 2, 5, B, 5, 2}。
// 那么我们是否可以把这道题分解为两个问题一来解决呢?
// 化繁为简,先把nums中所有元素异或起来,得到
// 10^10^A^2^5^B^5^2 = A^B。
// A B肯定是不同的数,既然是不同的数,A B一定存在某一位(假设是第x位)
// 上的数是不同的,而在二进制视角中,数字要么是1要么是0,
// 所以在第x位上要么A是1,B是0,要么B是1,A是0,这样才有A B在第x位上的
// 数是不同的。所以A B的异或A^B,在第x位上一定等于1 (1^0=1)。
// 
// 我们用 A^B第x位上的1,来把问题二分解成问题一。
// 我们设置一个辅助参数 one=1(二进制00000001),循环左移和A^B来做
// 逻辑与运算,来找这个第x位,如果one & (A^B) == 0,one就左移,
// 直到one & (A^B) != 0,说明找到了第x位。
//
// 然后循环遍历nums中的数,记为num,还记得第x位上要么A是1,B是0,
// 要么B是1,A是0,我们把num和one直接做与运算,
// 用if条件判断,把所有逻辑与的结果是1的数字,全部异或到int x参数上。
// 用if条件判断,把所有逻辑与的结果是0的数字,全部异或到int y参数上。
// 这样,不管第x位上A B是0还是1,我们都把它们分开到了不同的地方去异或
// 就把问题二分解成了两个问题一。最后直接返回x和y就行~



// 力扣
// 执行用时:1 ms, 在所有 Java 提交中击败了100.00%的用户
// 内存消耗:40.2 MB, 在所有 Java 提交中击败了34.85%的用户
class Solution {
    public int[] singleNumbers(int[] nums) {
		int x = 0, y = 0, t = 0, one = 1;
		for (int num : nums)
			t ^= num;
		while ((t & one) == 0)
			one <<= 1;
		for (int num : nums) {
			if ((num & one) != 0)
				x ^= num;
			else 
				y ^= num;
		}
		return new int[] {x, y};
    }
}




// 牛客
// 牛客比力扣多了一点,需要把小的数排在前面,其他都一样
// 运行时间:13ms,超过24.78%用Java提交的代码
// 占用内存:11092KB,超过51.91%用Java提交的代码
public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 
     * @return int整型一维数组
     */
    public int[] FindNumsAppearOnce (int[] array) {
		int x = 0, y = 0, t = 0, one = 1;
		for (int num : array)
			t ^= num;
		while ((t & one) == 0)
			one <<= 1;
		for (int num : array) {
			if ((num & one) != 0)
				x ^= num;
			else 
				y ^= num;
        }
        int[] res = new int[] {y, x};
        if (res[0] > res[1]) {
            int temp = res[0];
            res[0] = res[1];
            res[1] = temp;
        }
		return res;
    }
}



おすすめ

転載: blog.csdn.net/fisherish/article/details/114824198