leetcode
leetcode 401 ~ 450
数组中重复的数据

数组中重复的数据

难度:

标签:

题目描述

给你一个长度为 n 的整数数组 nums ,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现 一次两次 。请你找出所有出现 两次 的整数,并以数组形式返回。

你必须设计并实现一个时间复杂度为 O(n) 且仅使用常量额外空间的算法解决此问题。

 

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[2,3]

示例 2:

输入:nums = [1,1,2]
输出:[1]

示例 3:

输入:nums = [1]
输出:[]

 

提示:

  • n == nums.length
  • 1 <= n <= 105
  • 1 <= nums[i] <= n
  • nums 中的每个元素出现 一次两次

代码结果

运行时间: 41 ms, 内存: 23.9 MB


/*
 * 题目思路:
 * 给定一个长度为 n 的整数数组 nums,其中 nums 的所有整数都在范围 [1, n] 内,且每个整数出现一次或两次。
 * 要求找出所有出现两次的整数,并以数组形式返回。设计一个时间复杂度为 O(n) 且仅使用常量额外空间的算法。
 *
 * 解题思路:
 * 使用 Java Stream 实现上述逻辑
 */
 
import java.util.*;
import java.util.stream.*;
 
public class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> result = new ArrayList<>();
        IntStream.range(0, nums.length).forEach(i -> {
            int index = Math.abs(nums[i]) - 1;
            if (nums[index] < 0) {
                result.add(Math.abs(nums[i]));
            } else {
                nums[index] = -nums[index];
            }
        });
        return result;
    }
}

解释

方法:

该题解采用了一个巧妙的方法来在原地标记数组中已经访问过的数字,利用数组元素的符号进行标记。具体步骤如下: 1. 遍历数组中的每一个元素。 2. 使用当前元素的绝对值减一得到数组的索引位置 `idx`。 3. 检查位于 `idx` 的元素的符号。 - 如果该位置的元素为负数,说明之前已经访问过该位置,因此当前数字是重复的,将其加入结果列表。 - 如果该位置的元素为正数,将其变为负数,表示该位置已被访问过。 4. 遍历完成后,结果列表中的元素即为出现两次的数字。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,若数组中存在大于两次的重复数字,此方法能否正确处理并只返回两次的重复数字?
此算法无法区分一个数字出现两次还是多于两次。算法设计仅能检测到某个数字是否至少出现了两次。如果一个数字出现超过两次,算法在第二次遇到时就会记录下来,并不会在第三次或更多次遇到时做出区分。因此,如果数组中的数字出现超过两次,该算法仍然只会将其视为出现了两次,并加入结果列表中。
🦆
为什么在处理完整个数组后,没有将数组中的元素恢复到原始状态?这样做会对原数组产生什么影响?
该算法为了满足常数额外空间的要求,直接在输入数组上修改值以标记访问过的数字。算法结束后,数组中的元素值的正负被改变,不再保持原有的值。这意味着原数组被破坏,无法再用于其他目的。如果需要保留原数组,必须在应用此算法前做一份数组的拷贝。
🦆
在算法中使用元素的符号作为访问标记,这种方法在处理非整数或超出[1,n]范围的数字时是否还适用?
此算法假设所有元素都是范围在[1, n]内的整数,这是根据题目设定。如果元素是非整数或者不在[1, n]范围内,算法将不适用。首先,非整数没有明确的'索引位置',且对非整数使用索引访问或修改会引发错误。其次,如果数字超出范围,可能导致访问数组界外,引发数组越界错误。因此,算法仅适用于题目描述的特定情况。

相关问题

找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

 

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]

示例 2:

输入:nums = [1,1]
输出:[2]

 

提示:

  • n == nums.length
  • 1 <= n <= 105
  • 1 <= nums[i] <= n

进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内。