我遇到了Leetcode上的以下问题,并尝试用以下代码解决它,但似乎有一个更好的解决方案,可以利用XOR。Leetcode对XOR解决方案有一个描述,但是我无法整体掌握它。

我只是无法围绕我的头包围,为什么我们需要初始化缺少的变量,与数组的长度,为什么不用零初始化它,当我们用零初始化时,为什么不能这个algo找到了缺少的号码?有人可以解释一下吗?

以下是我的解决方案在我学习的Leetcode之前,建议的XOR解决方案更好,更快

class Solution {
    public int missingNumber(int[] nums) {
        if(nums.length == 1)
            return nums[0] == 0 ? 1 : 0;

        int missing = 0;
        boolean tempNums[] = new boolean[nums.length+1]; //cuz one is missing

        for(int i:nums) {
            tempNums[i] = true;
        }

        for(int i=0; i<tempNums.length; i++)
            if(!tempNums[i]) {
                missing = i;
                break;
            }
        return missing;
    }
}
.

有帮助吗?

解决方案

让我们使用更简单的示例来验证事实。

假设 $ n= 1 $ ,即,我们被给出一个包含从0,1的一个(独特)编号的数组。

  • 如果给定的数字为0,则缺少的数字必须是 $ 1= 1 \ land0 $
  • 如果给定的数字为1,则缺少的数字必须是 $ 0= 1 \ land1 $

总结,如果给定的数字是 $ a $ ,则缺少的号码是 $ 1 \ land a= n \ Land A \ not= 0 \ Land A $


一般情况下这个魔法背后的根本原因是什么?

它掉出了按位XOR运算符,通常由“ $ \ land $ ”以编程语言表示,表现类似于普通加运算符。

  • 它是换向关联。所以行动顺序根本无关紧要。
  • $ 0 $ 函数为零,即 $ a \ land 0= a $ 。所以 $ 0 $ 可以删除。
  • $ a \ land a= 0 $ 为每个数字 $ a $ 。因此,如果相同的数字出现两次,则它们互相取消。

在编程语言之外,按位XOR更常写为“ $ \ oplus $ ”,其中plus符号“ $ + $ ”中央提醒我们,它表现得像普通的补充。

现在考虑表达式, $$(0 \ oplus1 \ oplus2 \ oplus3 \ cdots \ oplus n)\ oplus(a_0 \ oplus a_1 \ oplus a_2 \ cdots \ oplus a_ { n-1})。 $$ 每当有一对相同的数字时,我们都可以删除它们。因此,所有数字都在彼此之间取消,除了缺少的号码,因为缺少的号码是 $$ 0 \ oplus1 \ oplus2 \ oplus3 \ cdots \ oplus n $的唯一数字$ 但不是 $$ a_0 \ oplus a_1 \ oplus a_2 \ cdots \ oplus a_ {n-1}。$$ so,

$$(0 \ oplus1 \ oplus2 \ oplus3 \ cdots \ oplus n)\ oplus(a_0 \ oplus a_1 \ oplus a_2 \ cdots \ oplus a_ {n-1})= \文本{缺少的号码} $$

让我们在左侧更改“求和”的顺序。我们可以将 $ 0 $ 使用 $ a_0 $ $ 1 $ 使用 $ a_1 $ $ 2 $ 使用 $ a_2 $ $ \ cdots $ $ n-1 $ $ a_ {n-1} $ ,只留下 $ n $ 未配对。我们看到左手侧是 $$(0 \ oplus a_0)\ oplus(1 \ oplus a_1)\ oplus(2 \ oplus a_2)\ oplus \ cdots(n-1 \ oplus a_ {n-1} )\ oplus n。 $$ 现在,只需将 $ n $ 移动到表达式的前面。


“我只是无法围绕我的头包围为什么我们需要初始化缺少的变量,与数组的长度。为什么不用零初始化,当我们用零初始化时,为什么不能找到缺少的原因号码?“

$ n $ 初始化缺失变量,初始化丢失变量没有什么特别的特别之处。您肯定可以使用任何数字初始化,包括零。然后,应将剩余的数字配对 $ a_0,a_2,\ cdots,a_ {n-1} $ 任意< / em>,每个数字一次)。例如,我们有

$$ 0 \ oplus(1 \ oplus a_0)\ oplus(2 \ oplus a_1)\ oplus \ cdots(n \ oplus a_ {n-1})=text {缺少的号码} $$

事实上,我们根本不必做配对。我们甚至可以直接预编译 $$ f(n)= 0 \ oplus1 \ oplus2 \ oplus3 \ cdots \ oplus n =begin {案例} n&\ text {if} n= 0 \ pmod4 \\ 1&\ text {if} n= 1 \ pmod4 \\ n + 1&\ text {if} n= 2 \ pmod4 \\ 0&\ text {if} n= 3 \ pmod4 \\ \结束{案例} $$ 然后计算 $$ f(n)\ oplus a_0 \ oplus a_1 \ oplus a_2 \ cdots \ oplus a_ {n-1},$$ 这也会产生缺失的号码。因此,我们有以下更快的程序来计算缺失的号码。

public int missingNumber(int[] nums) {
    final int length = nums.length;
    // missing = length, 1, length + 1, 0 when length = 0, 1, 2, 3 mod 4.
    int missing = length % 2 == 0 ? length + (length / 2 % 2) : (length + 1) / 2 % 2;
    for (int i : nums) missing ^= i;

    return missing;
}
.

上述方法非常类似于方法Leetcode的#4高斯公式

其他提示

从任何n个整数的列表开始。复制整数并计算XOR如果这2n整数。结果是什么?以任何方式重新排列2N整数并计算其XOR。结果是什么。从列表中删除数字X并计算XOR。结果是什么?删除另一个数字y并计算XOR。结果是什么?

现在回到您的问题,并在您之前给出的答案告诉您您的结果将是什么。

许可以下: CC-BY-SA归因
不隶属于 cs.stackexchange
scroll top