Java&C++题解与拓展——leetcode442.数组中重复的数据【么的新知识】

这篇博客分享了两种O(n)时间复杂度、O(1)空间复杂度的解决方案来找出数组中重复的数字。第一种是原地哈希,通过交换元素位置和标记负数来找到重复项;第二种是正负号标记法,利用正负号来标记已遍历和重复的数字。这两种方法巧妙且高效,适合解决数组重复问题。
摘要由CSDN通过智能技术生成
每日一题做题记录,参考官方和三叶的题解

题目要求

在这里插入图片描述

思路一:原地哈希

  • 按正常排序的话 a a a应该在数组中 a − 1 a-1 a1的位置,也就是 n u m s [ a − 1 ] = a nums[a-1]=a nums[a1]=a
  • 那就遍历数组中的每一个数,把它们放在正确的位置上;
  • 在放的过程中若该位置已有正确的数,那说明重复了,当前数加入答案,同时把当前数置为负数表示已处理过;
  • 否则就交换这两个数的位置。

Java

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new ArrayList<>();
        int n = nums.length;
        for(int i = 0; i < n; i++) {
            int cur = nums[i];
            if(cur < 0 || cur - 1 == i) // 遍历过 或 已就位
                continue;
            if(nums[cur - 1] == cur) { // 目标位置已就位
                res.add(cur);
                nums[i] *= -1; // 置负数表示已遍历
            }
            else { // 交换位置使其就位
                int tmp = nums[cur - 1];
                nums[cur - 1] = cur;
                nums[i--] = tmp;
            }
        }
        return res;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

C++

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> res;
        int n = nums.size();
        for(int i = 0; i < n; i++) {
            int cur = nums[i];
            if(cur < 0 || cur - 1 == i) // 遍历过 或 已就位
                continue;
            if(nums[cur - 1] == cur) { // 目标位置已就位
                res.push_back(cur);
                nums[i] *= -1; // 置负数表示已遍历
            }
            else { // 交换位置使其就位
                int tmp = nums[cur - 1];
                nums[cur - 1] = cur;
                nums[i--] = tmp;
            }
        }
        return res;
    }
};
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

思路二:正负号标记

  • 其实和上面思路差不多,只不过不交换位置,只是用正负号做标记;
  • 将当前数应该去的位置的值置为负数;
  • 遍历时发现负则重复。

Java

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        List<Integer> res = new ArrayList<>();
        int n = nums.length;
        for(int i = 0; i < n; i++) {
            int cur = Math.abs(nums[i]); // 取原始数据
            if(nums[cur - 1] > 0) // 置为负表示遍历过
                nums[cur - 1] *= -1;
            else // 负表示已有该数
                res.add(cur);            
        }
        return res;
    }
}
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

C++

class Solution {
public:
    vector<int> findDuplicates(vector<int>& nums) {
        vector<int> res;
        int n = nums.size();
        for(int i = 0; i < n; i++) {
            int cur = abs(nums[i]); // 取原始数据
            if(nums[cur - 1] > 0) // 置为负表示遍历过
                nums[cur - 1] *= -1;
            else // 负表示已有该数
                res.push_back(cur);            
        }
        return res;
    }
};
  • 时间复杂度:$ O(n)$
  • 空间复杂度: O ( 1 ) O(1) O(1)

总结

虽然是个中等题,但还是一下就想到了排序,只不过没想到这么巧妙的标记法,还要加油呀。

倒是比昨天的题简单太多……


欢迎指正与讨论!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值