【LeetCode】448. 找到数组中没有出现的元素

本文介绍了一种在O(n)时间内查找整数数组中缺失元素的方法,利用数组索引与元素值的关系,通过标记已出现的元素,最终找出未出现在数组中的元素。此方法巧妙地避免了使用额外空间。

问题描述

Given an array of integers where 1 ≤ a[i] ≤ n (n = size of array), some elements appear twice and others appear once.

Find all the elements of [1, n] inclusive that do not appear in this array.

Could you do it without extra space and in O(n) runtime? You may assume the returned list does not count as extra space.

给定一个整数数组,其中 1 ≤ a[i] ≤ n (n = 数组大小),有些元素出现两次,有些元素出现一次。
找到 [1, n] 中不出现在这个数组中的所有元素。
你能在 O(n) 运行时不需要额外的空间吗?你可以假定返回的列表不算作额外的空间。

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

输出:
[5,6]

Python 实现

从题目条件可以知道,数组中的元素可以与数组索引形成一个对应关系。举个理想的情况,一个长度为n的数组,其索引为 0 到 n-1,其元素为 1 - n。这样子索引与元素值之间的关系就是:索引 + 1 = 元素值。因此,我们可以通过数组中出现的元素值对相应索引对应的值进行标记,最后没有被标记的索引位置,相应的就是没有出现的元素。

具体做法是:

  • 通过一次遍历,将以出现元素的值减 1 为索引的元素乘 -1;
  • 没有出现过的元素,对应 -1 的索引位置的值仍然为正数。
class Solution(object):
    def findDisappearedNumbers(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        
        # Marked the index with element by multiplying -1.
        for idx in range(len(nums)):
            num = nums[idx]
            if nums[abs(num)-1] > 0:
                nums[abs(num)-1] *= -1
            
        # The indeces of remain positive numbers, adding one, are the targets.
        ret_list = []    
        for idx in range(len(nums)):
            if nums[idx] > 0:
                ret_list.append(idx+1)
        
        return ret_list

链接:https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array/

<think>好的,我需要帮助用户找到用Java实现LeetCode第26题“删除有序数组中的重复项”的解决方案。首先,我得先理解题目要求。题目说给定一个按非递减顺序排列的数组,需要原地删除重复的元素,使得每个元素只出现一次,并返回新数组的长度。同时,必须使用O(1)的额外空间,也就是不能使用额外的数组结构,只能在原数组上修改。 接下来,我应该回顾用户提供的参考内容。用户引用了几个相关的解决方案,其中引用[5]提到了快慢指针的方法。Python示例中使用了快慢指针,i从0开始,j从1开始,当nums[j]不等于nums[i]时,i移动并保存nums[j]的值。这应该是一个双指针的典型解法,应该可以应用到Java中。 用户现在需要的是Java版本的解法,所以需要将Python或C++的代码转换成Java。在引用[5]的示例中,Java代码的结构大致是:检查数组是否为空,初始化i=0,然后循环j从1到数组末尾,如果nums[j]不等于nums[i],则i自增,并将nums[j]赋值给nums[i]。最后返回i+1作为新长度。 我需要确保Java代码的正确性。首先,处理边界情况,比如数组长度为0的情况,应该返回0。但根据题目约束,数组长度至少为1,所以可能不需要处理。不过为了代码的健壮性,可以保留检查。 然后,循环部分,用for循环遍历数组,快指针j从1开始,慢指针i从0开始。每次比较nums[j]和nums[i],如果不相等,就将i加1,并复制nums[j]到nums[i]的位置。这样,i始终指向最后一个不重复的元素,而j不断寻找下一个不同的元素。 需要注意的是,题目要求原地修改数组,所以直接操作原数组即可。此外,返回的长度是i+1,因为i是索引,从0开始,所以元素个数是索引加1。 现在,把这些逻辑用Java代码写出来。例如: public int removeDuplicates(int[] nums) { if (nums.length == 0) return 0; int i = 0; for (int j = 1; j < nums.length; j++) { if (nums[j] != nums[i]) { i++; nums[i] = nums[j]; } } return i + 1; } 这样应该就可以解决问题了。同时,需要解释代码的步骤,比如初始化两个指针,遍历数组,更新慢指针的位置,并覆盖重复项。这样用户能理解每一步的作用。 可能还需要分析时间和空间复杂度。时间复杂度是O(n),因为只遍历一次数组。空间复杂度是O(1),只用了常数级的额外变量。 最后,生成相关问题,比如时间复杂度的分析,或者如果允许最多重复两次的情况如何处理(例如LeetCode第80题),或者其他相关的双指针问题。 总结来说,我需要将已有的解决方案转换为Java,并确保正确性和符合题目的要求,同时给出清晰的解释和相关的问题。</think>### Java实现LeetCode第26题'删除有序数组中的重复项' #### 题目要求 给定一个按**非递减顺序排列**的整数数组 `nums`,需要**原地删除重复元素**,使得每个元素只出现一次,并返回新数组的长度。要求使用 $O(1)$ 的额外空间复杂度[^3]。 #### 实现思路 使用**双指针法(快慢指针)**: 1. **慢指针 `i`**:指向当前唯一元素的最后一个位置。 2. **快指针 `j`**:遍历数组,寻找下一个与 `nums[i]` 不同的元素。 3. 当 `nums[j] != nums[i]` 时,将 `nums[j]` 赋值给 `nums[i+1]`,并移动 `i`。 #### 代码实现 ```java public int removeDuplicates(int[] nums) { if (nums.length == 0) return 0; int i = 0; for (int j = 1; j < nums.length; j++) { if (nums[j] != nums[i]) { i++; nums[i] = nums[j]; } } return i + 1; } ``` #### 代码解释 1. **边界处理**:若数组为空,直接返回0(题目约束数组长度至少为1,此判断可省略)。 2. **初始化指针**:`i=0` 作为慢指针,`j=1` 作为快指针。 3. **遍历数组**: - 当 `nums[j]` 与 `nums[i]` 不同时,说明找到新唯一元素,将 `i` 后移一位,并更新 `nums[i]`。 4. **返回结果**:`i+1` 即为新数组的长度。 #### 复杂度分析 - **时间复杂度**:$O(n)$,遍历一次数组。 - **空间复杂度**:$O(1)$,仅使用常数级额外变量[^5]。 #### 示例说明 输入:`nums = [1,1,2]` 执行过程: 1. `i=0`, `j=1`:`nums[1]=nums[0]`,跳过。 2. `j=2`:`nums[2]=2 != nums[0]=1`,`i` 移动到1,`nums[1]=2`。 3. 最终数组前 `i+1=2` 个元素为 `[1,2]`,返回长度2。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值