【算法】组中元素全是1~n之间的整数问题

来源:互联网 发布:利驰软件怎么样 编辑:程序博客网 时间:2024/05/21 19:44

数组中数全是1~n的范围内的题

这部分之前是在LeetCode的好题总结里的,不过在打算给类似问题专题化之后,就单独把这部分拿了来了,然后又新加了一些总结和解法。

长度为n的数组,其中元素全部为1~n,则这种题有一个通用的解法:
循环替换 num[num[i]] = num[i]直到不能替换为止。然后再继续。具体操作上,可以不断的做swap(num[i],num[num[i]])这样写起来代码更短,更方便。

还有一种比较trick的思路就是,nums[i]的数组,将其在nums[nums[i]]这个位置坐上一些标记。

对于这类数组一个最经典的两个问题就是:

  1. 给定一个长度为n的数组,数组中元素是1~n之间的数乱序排列,将其用O(n)时间复杂度排序
  2. 给定一个长度为n-1的数组,数组中元素是1~n之间的数乱序排列,但少了一个数,让O(n)的时间内找出这个缺少的这个数。

对于第一个问题,就直接采用上面说的办法,不断轮换,就可以了。【其实难道不是直接输出从1~n不就好了吗,更方便,笑】
对于第二个问题,也是采用上面的方法,不断轮换,然后再遍历一遍,发现num[i]位置上是否是i+1如果不是则说明这个元素就是的了。其实还有一个别的解法,就是将数组中所有元素都给异或一遍,然后再跟1~n都给异或一遍,则最后剩下的那个值就是缺失的元素了。

LeetCode 上关于这种数组有以下三道题:
448. Find All Numbers Disappeared in an Array这道题是在1~n数组中全部找到其中消失的元素。
Input:
[4,3,2,7,8,2,3,1]
Output:
[5,6]

    vector<int> findDisappearedNumbers(vector<int>& nums) {        vector<int> res;        for(int i=0;i<nums.size();i++){            while(nums[i] != nums[nums[i]-1])                swap(nums[i],nums[nums[i]-1]);        }        for(int i=0;i<nums.size();i++)            if(nums[i]-1 != i)                res.push_back(i+1);        return res;    }

442. Find All Duplicates in an Array
找一个数组中(数组中全是1~n的数,但是有重复的),找出其中全部的重复元素。
Input:
[4,3,2,7,8,2,3,1]
Output:
[2,3]
其实这道题和上面那道题是一样的,如果采用不断swap的方法,最后缺失的位置上会剩下重复的元素。如果采用轮换替换的方法,则会变得麻烦。

    vector<int> findDuplicates(vector<int>& nums) {        vector<int> res;        for(int i=0;i<nums.size();i++){            while(nums[i] != nums[nums[i]-1])                swap(nums[i],nums[nums[i]-1]);        }        for(int i=0;i<nums.size();i++)            if(nums[i]!=i+1)                res.push_back(nums[i]);        return res;    }

这道题呢,还有一个办法,可以改变原来的数组【其实也是改变了,只不过最后又修复了】,就是每次找到nums[i]这个元素了,把nums[nums[i]]标记为原来的相反数,如果nums[nums[i]]就已经是复数了,则说明这个元素重复了。然后最后再把所有元素取一个绝对值,就修复了。代码如下

    vector<int> findDuplicates(vector<int>& nums) {        vector<int> res;        for(int i=0;i<nums.size();i++){            if(nums[abs(nums[i])-1] <0)                res.push_back(abs(nums[i]));            else                nums[abs(nums[i])-1] = -nums[abs(nums[i])-1];        }        for(auto &i:nums)            i = abs(i);        return res;    }

41. First Missing Positive找出一列数中,假如将其排序的话,缺失的第一个正整数(即不包括0)
Given [1,2,0] return 3,
and [3,4,-1,1] return 2.
还是用上面的解法,不过注意这道题有个tricky的地方在于nums[i]是换nums[nums[i]-1]还是换nums[nums[i]]
因为题目中要求找出缺失的第一个正整数,所以需要换nums[nums[i]-1],因为这样保证如果1就应该出现在第一个位置,如果没有出现则说明缺少了1。如果题目中要求找出确实的第一个自然数(包括0)则需要换nums[nums[i]];同理类比可得如果要找从2开始缺失的数,则需要换nums[nums[i]-2]

    int firstMissingPositive(vector<int>& nums) {        for(int i=0;i<nums.size();i++){            while(nums[i]>0 && nums[i]<=nums.size()&&nums[i] != nums[nums[i]-1])                swap(nums[i],nums[nums[i]-1]);        }        for(int i=0;i<nums.size();i++)            if(nums[i]!=i+1)                return i+1;        return nums.size()+1;    }
0 0
原创粉丝点击