欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 财经 > 创投人物 > 排序题目:丢失的数字

排序题目:丢失的数字

2024/11/30 10:36:51 来源:https://blog.csdn.net/stormsunshine/article/details/125456181  浏览:    关键词:排序题目:丢失的数字

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
      • 进阶
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法三
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法四
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法五
    • 预备知识
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:丢失的数字

出处:268. 丢失的数字

难度

2 级

题目描述

要求

给定一个数组 nums \texttt{nums} nums,数组包含 n \texttt{n} n 个在范围 [0, n] \texttt{[0, n]} [0, n] 内的不同整数,返回该范围内唯一没有在数组中出现的数。

示例

示例 1:

输入: nums = [3,0,1] \texttt{nums = [3,0,1]} nums = [3,0,1]
输出: 2 \texttt{2} 2
解释: n = 3 \texttt{n = 3} n = 3,因为有 3 \texttt{3} 3 个数字,所以所有的数字都在范围 [0,3] \texttt{[0,3]} [0,3] 内。 2 \texttt{2} 2 是丢失的数字,因为它没有出现在 nums \texttt{nums} nums 中。

示例 2:

输入: nums = [0,1] \texttt{nums = [0,1]} nums = [0,1]
输出: 2 \texttt{2} 2
解释: n = 2 \texttt{n = 2} n = 2,因为有 2 \texttt{2} 2 个数字,所以所有的数字都在范围 [0,2] \texttt{[0,2]} [0,2] 内。 2 \texttt{2} 2 是丢失的数字,因为它没有出现在 nums \texttt{nums} nums 中。

示例 3:

输入: nums = [9,6,4,2,3,5,7,0,1] \texttt{nums = [9,6,4,2,3,5,7,0,1]} nums = [9,6,4,2,3,5,7,0,1]
输出: 8 \texttt{8} 8
解释: n = 9 \texttt{n = 9} n = 9,因为有 9 \texttt{9} 9 个数字,所以所有的数字都在范围 [0,9] \texttt{[0,9]} [0,9] 内。 8 \texttt{8} 8 是丢失的数字,因为它没有出现在 nums \texttt{nums} nums 中。

数据范围

  • n = nums.length \texttt{n} = \texttt{nums.length} n=nums.length
  • 1 ≤ n ≤ 10 4 \texttt{1} \le \texttt{n} \le \texttt{10}^\texttt{4} 1n104
  • 0 ≤ nums[i] ≤ n \texttt{0} \le \texttt{nums[i]} \le \texttt{n} 0nums[i]n
  • nums \texttt{nums} nums 中的所有数字各不相同

进阶

你能否实现 O(n) \texttt{O(n)} O(n) 时间复杂度和 O(1) \texttt{O(1)} O(1) 空间复杂度的解法?

解法一

思路和算法

首先将数组 nums \textit{nums} nums 升序排序。如果数组中没有数字丢失,则排序后的数组中,每个下标处的元素值都等于下标值。

假设丢失的数字是 x x x 0 ≤ x ≤ n 0 \le x \le n 0xn,则排序后的数组中,对于任意 0 ≤ i < x 0 \le i < x 0i<x 都有 nums [ i ] = i \textit{nums}[i] = i nums[i]=i。分别考虑 x < n x < n x<n x = n x = n x=n 的两种情况:

  • 如果 x < n x < n x<n,则 nums [ x ] ≠ x \textit{nums}[x] \ne x nums[x]=x x x x 是第一个元素值不等于下标值的下标;

  • 如果 x = n x = n x=n,则数组中的所有下标处的元素值都等于下标值。

因此只要遍历排序后的数组即可得到丢失的数字。遍历过程中,第一个元素值不等于下标值的下标即为丢失的数字。如果遍历结束之后没有发现元素值不等于下标值的下标,则范围 [ 0 , n − 1 ] [0, n - 1] [0,n1] 内的数字都不丢失,丢失的数字是 n n n

代码

class Solution {public int missingNumber(int[] nums) {Arrays.sort(nums);int n = nums.length;for (int i = 0; i < n; i++) {if (nums[i] != i) {return i;}}return n;}
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,遍历数组需要 O ( n ) O(n) O(n) 的时间,总时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( log ⁡ n ) O(\log n) O(logn),其中 n n n 是数组 nums \textit{nums} nums 的长度。排序需要 O ( log ⁡ n ) O(\log n) O(logn) 的递归调用栈空间。

解法二

思路和算法

为了找到丢失的数字,可以使用哈希集合存储数组中的数字,然后寻找不在哈希集合中的数字。

由于所有的数字都在范围 [ 0 , n ] [0, n] [0,n] 内,因此依次遍历该范围的数字,判断每个数字是否在哈希集合中。具体做法是,首先遍历范围 [ 0 , n − 1 ] [0, n - 1] [0,n1] 内的每个数字,如果遇到不在哈希集合中的数字,则该数字是丢失的数字,返回该数字。如果范围 [ 0 , n − 1 ] [0, n - 1] [0,n1] 内的每个数字都在哈希集合中,则丢失的数字是 n n n,返回 n n n

代码

class Solution {public int missingNumber(int[] nums) {Set<Integer> set = new HashSet<Integer>();for (int num : nums) {set.add(num);}int n = nums.length;for (int i = 0; i < n; i++) {if (!set.contains(i)) {return i;}}return n;}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 一次将数组中的所有数字加入哈希集合,然后需要遍历范围 [ 0 , n ] [0, n] [0,n] 内的每个数字寻找丢失的数字。

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。哈希集合需要 O ( n ) O(n) O(n) 的空间。

解法三

思路和算法

解法二创建哈希集合需要 O ( n ) O(n) O(n) 的空间,如果可以原地哈希,则可以将空间复杂度降低到 O ( 1 ) O(1) O(1)

具体做法是,对于数组 nums \textit{nums} nums 的每个下标 i i i,如果 nums [ i ] < n \textit{nums}[i] < n nums[i]<n nums [ i ] ≠ i \textit{nums}[i] \ne i nums[i]=i,则将下标 nums [ i ] \textit{nums}[i] nums[i] 与下标 i i i 处的元素交换,交换之后 nums [ i ] \textit{nums}[i] nums[i] 的元素值等于下标值,重复该交换过程直到 nums [ i ] = n \textit{nums}[i] = n nums[i]=n nums [ i ] = i \textit{nums}[i] = i nums[i]=i,此时下标 i i i 处的元素无法继续交换。

当每个下标的交换操作都结束之后,遍历数组 nums \textit{nums} nums 寻找丢失的数字。遍历过程中,第一个元素值不等于下标值的下标即为丢失的数字。如果遍历结束之后没有发现元素值不等于下标值的下标,则范围 [ 0 , n − 1 ] [0, n - 1] [0,n1] 内的数字都不丢失,丢失的数字是 n n n

代码

class Solution {public int missingNumber(int[] nums) {int n = nums.length;for (int i = 0; i < n; i++) {while (nums[i] < n && nums[i] != i) {swap(nums, nums[i], i);}}for (int i = 0; i < n; i++) {if (nums[i] != i) {return i;}}return n;}public void swap(int[] nums, int index1, int index2) {int temp = nums[index1];nums[index1] = nums[index2];nums[index2] = temp;}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 一次,每次会将一个元素交换到正确的下标位置,因此每个元素的访问次数是常数次,时间复杂度是 O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)

解法四

思路和算法

由于数组 nums \textit{nums} nums 中只有一个元素丢失,因此只要得到范围 [ 0 , n ] [0, n] [0,n] 内的所有整数之和以及数组 nums \textit{nums} nums 的所有元素之和,两者相减即可得到丢失的数字。

根据高斯公式可知,范围 [ 0 , n ] [0, n] [0,n] 内的所有整数之和是 n ( n + 1 ) 2 \dfrac{n(n + 1)}{2} 2n(n+1),因此可以在 O ( 1 ) O(1) O(1) 的时间内得到范围 [ 0 , n ] [0, n] [0,n] 内的所有整数之和。

代码

class Solution {public int missingNumber(int[] nums) {int sum = 0;for (int num : nums) {sum += num;}int n = nums.length;return n * (n + 1) / 2 - sum;}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 一次计算数组元素之和。

  • 空间复杂度: O ( 1 ) O(1) O(1)

解法五

预备知识

该解法涉及到位运算中的按位异或运算。用 ⊕ \oplus 表示按位异或运算符,按位异或运算具有以下性质。

  • 交换律:对于任意整数 a a a b b b,有 a ⊕ b = b ⊕ a a \oplus b = b \oplus a ab=ba

  • 结合律:对于任意整数 a a a b b b c c c,有 ( a ⊕ b ) ⊕ c = a ⊕ ( b ⊕ c ) (a \oplus b) \oplus c = a \oplus (b \oplus c) (ab)c=a(bc)

  • 归零律:对于任意整数 a a a,有 a ⊕ a = 0 a \oplus a = 0 aa=0

  • 恒等律:对于任意整数 a a a,有 0 ⊕ a = a ⊕ 0 = a 0 \oplus a = a \oplus 0 = a 0a=a0=a

思路和算法

数组 nums \textit{nums} nums 中有 n n n 个整数,如果在这 n n n 个整数后面添加范围 [ 0 , n ] [0, n] [0,n] 内的每个整数各一个,则添加 n + 1 n + 1 n+1 个整数,共有 2 n + 1 2n + 1 2n+1 个整数。这 2 n + 1 2n + 1 2n+1 个整数中,未丢失的数字在前 n n n 个整数中以及在后 n + 1 n + 1 n+1 个整数中各出现一次,丢失的数字只在后 n + 1 n + 1 n+1 个整数中出现一次,因此每个未丢失的数字出现两次,丢失的数字出现一次。

利用按位异或运算的性质,对上述 2 n + 1 2n + 1 2n+1 个整数计算按位异或的结果。所有出现两次的数字经过按位异或运算之后的结果是 0 0 0,只有出现一次的数字在按位异或运算之后保留,因此上述 2 n + 1 2n + 1 2n+1 个整数的按位异或的结果即为丢失的数字。

代码

class Solution {public int missingNumber(int[] nums) {int xor = 0;for (int num : nums) {xor ^= num;}int n = nums.length;for (int i = 0; i <= n; i++) {xor ^= i;}return xor;}
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 nums \textit{nums} nums 的长度。需要遍历数组 nums \textit{nums} nums 一次以及遍历范围 [ 0 , n ] [0, n] [0,n] 内的所有整数计算按位异或的结果。

  • 空间复杂度: O ( 1 ) O(1) O(1)

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com