给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。
找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
示例:
输入:
[4,3,2,7,8,2,3,1]
输出:
[5,6]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/find-all-numbers-disappeared-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
示例 1:
输入:
[2, 3, 1, 0, 2, 5, 3]
输出:2 或 3
限制:
2 <= n <= 100000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
两个题其实想法是差不多的,就放到一起来说了。
在不开辟新空间的情况下,我们要来达到题目要求,那么我们只能在原数组上进行操作。那如何在原数组上操作?而且还需要线性时间。
我们知道数组元素的范围一定是1~n 或者 0~ n-1,这样就优化了排序的时间,普通的数组排序时间会消耗很多,但这个比较特殊,我们让每个数回归到数组中与其对应的索引上,我们就完成了所谓的排序,如果有不一样的,那么这个数必定不会和它的索引相对应,这样我们就找出了消失的数组,如果交换过程中,目标即该数对应的索引的位置上已经对应了,那么就说明这个数重复了,返回这个数就可以了。
在这里我只用这个解法做了第一个题。
1 vector<int> findDisappearedNumbers(vector<int>& nums) { 2 vector<int> v; 3 for(int i = 0; i < nums.size(); i++) { 4 while ((nums[i] != i + 1) && (nums[nums[i] - 1] != nums[i])) { 5 int t = nums[i]; 6 nums[i] = nums[t - 1]; 7 nums[t - 1] = t; 8 } 9 } 10 for(int i = 0; i < nums.size(); i++) { 11 if(nums[i] != i + 1) 12 v.push_back(i + 1); 13 } 14 return v; 15 }
这是官方题解,以下解法来源于这里。
官方的解法巧妙地利用了求余,也是在原数组上进行修改。
我们根据求余数求得该数对应的索引,让该索引的值 +n,循环完毕后,没出现的那个数对应的索引的值一定是小于n的,而大于等于2n的就是出现两次或两次以上的。
这里我只写了第二个题的解法
1 int findRepeatNumber(vector<int>& nums) { 2 int n = nums.size(); 3 for(int i = 0; i < n; i++) { 4 int x = nums[i] % n; 5 nums[x] += n; 6 } 7 for(int i = 0; i < n; i++) { 8 if(nums[i] >= 2 * n) 9 return i; 10 } 11 return -1; 12 }
原文:https://www.cnblogs.com/lisuhang/p/14401064.html