【第0007页 · 数组】数组中重复的数据(如何实现数组的原地修改)

【前言】本文以及之后的一些题解都会陆续整理到目录中,若想了解全部题解整理,请看这里:

【第0007页 · 数组】数组中重复的数据(如何实现数组的原地修改)_第1张图片

第0007页 · 数组中重复的数据

        今天,我们来看一个在实际工作中运用不多,但是对于一些算法题还是有必要的奇技淫巧——数组的原地修改。下面我们将通过两道题目来学习这种技巧。

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

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

【解题分析】这道题本来十分简单,但是如果加上一个要求:在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 可以假定返回的数组不算在额外空间内。那么这道题就有些内容可以说了。

        这里我们先来讲解一下这种原地修改的想法:首先,由于 nums 的长度恰好为 n,而我们要查找的数字范围均在 [1, n] 中,那么我们不妨将位置 k 处的值当成数字 k + 1 是否出现的凭证。以上是 Hash 的思想。

        接下来,我们需要考虑如何才能使位置 k 处的值能够代表数字 k + 1 是否出现过。我们提供一种想法是如果 k + 1 出现过,需要将位置 k 处的值加上 n,因为本来数组中所有的数都小于 n,只能是由于出现过而导致大于 n。根据以上想法,我们就可以使位置 k 处的值能够代表数字 k + 1 是否出现过。

【源码展示】

class Solution {
public:
    vector findDisappearedNumbers(vector& nums) {
    int n = nums.size();
    for (int num : nums) {
        int x = (num - 1) % n;
        nums[x] += n;
    }
    vector ret;
    for (int i = 0; i < n; i++) {
        if (nums[i] <= n) {
            ret.push_back(i + 1);
        }
    }
    return ret;
    }
};

         解决完上面这道题,我们再来看今天的第二题,中间也需要用到类似的思想。

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

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

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

【解题分析】这里和上面一题的要求几乎一致,思路也差不多,就留给读者自行思考了

【源码展示】

class Solution {
public:
    vector findDuplicates(vector& nums) {
        int size = nums.size();

        for (int i = 0; i< size; i++) {
            // Swap until appear in right pos
            while (nums[i] != nums[nums[i] - 1]) {
                swap(nums[i], nums[nums[i] - 1]);
            }
        }

        vector ans;

        for (int i = 0; i < size; i++) {
            if (nums[i] != (i+1)) {
                ans.emplace_back(nums[i]);
            }
        }

        return ans;

    }
};

你可能感兴趣的:(南星六月雪的手札,算法,学习,笔记,c++,leetcode)