您的位置:首页 > Web前端

数组中的重复(缺失)数字 剑指offer3 及扩展

2017-09-01 21:23 330 查看

这些题目首先都是未排序的

1、 136 single number

在数组中所有数字都出现两次,只有一个数字出现一次,求出这个数。

思路1:使用位运算,两个相同的数异或为0。

时间复杂度 n

思路2:建立一个哈希表,出现了就计入,再次出现就减去,最后寻找只出现一次的那个数。 nlogn,需要额外空间

class Solution {
public:
int singleNumber(vector<int>& nums) {
set<int> res;
for(auto n:nums)
{
if(res.find(n)!=res.end()) res.erase(n);
else res.insert(n);
}
return *res.begin();
}
};

2、268. Missing Number

Given an array containing n distinct numbers taken from 
0, 1, 2, ..., n
,
find the one that is missing from the array.

For example,

Given nums = 
[0, 1, 3]
 return 
2
.

找到仅有的缺失的数

思路1:使用抑或将数字和标号抑或,最后再跟size抑或,最后剩下的就是缺失的数

思路2:排序,求差值(不好)


3 41. First Missing Positive

Given an unsorted integer array, find the first missing positive integer.

For example,

Given 
[1,2,0]
 return 
3
,

and 
[3,4,-1,1]
 return 
2
.

Your algorithm should run in O(n) time and uses constant space.
思路:本来正确的数列,有一个数被代替了(可能被0或者负数代替),这样,将每一个在1-n范围的数都排回去,那么丢失的那个数上一定是替代的那个数
class Solution {
public:
int firstMissingPositive(vector<int>& nums) {
int n=nums.size();
for(int i=0;i<n;i++)//桶排序
{
while(nums[i]>0&&nums[i]<=n&&nums[i]!=i+1&&nums[i]!=nums[nums[i]-1])//不加最后一个判断,会进入死循环,因为重复的数字可能在n范围之内
swap(nums[i],nums[nums[i]-1]);
}
for(int i=0;i<n;i++)
{
if(nums[i]!=i+1)
return i+1;
}
return n+1;

}
};

4
 448. Find All Numbers Disappeared in an Array

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.

Example:
Input:
[4,3,2,7,8,2,3,1]

Output:
[5,6]

思路1:将当前的数和它应该在的位置交换,直到有了应该是这个位置的数,如果出现与交换的位置相同的数,那么这个数就是一个重复值。转到下一个数,遍历一遍,后在遍历一遍,看与标号不相等的数,把标号写入输出即可。
class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {

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


思路2:将当前数指向的那个数变成负数,缺失的数所指向的位置不会变成负数

class Solution {
public:
vector<int> findDisappearedNumbers(vector<int>& nums) {
int len = nums.size();
for(int i=0; i<len; i++) {
int m = abs(nums[i])-1; // index start from 0
nums[m] = nums[m]>0 ? -nums[m] : nums[m];
}
vector<int> res;
for(int i = 0; i<len; i++) {
i
10697
f(nums[i] > 0) res.push_back(i+1);
}
return res;
}
};


5 442. Find All Duplicates in an Array 1-n的范围,有的数出现两次,找出这些数

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

Find all the elements that appear twice in this array.

Could you do it without extra space and in O(n) runtime?

Example:

Input:
[4,3,2,7,8,2,3,1]

Output:
[2,3]

与上一题基本一样
思路1:将当前的数和它应该在的位置交换,直到有了应该是这个位置的数,如果出现与交换的位置相同的数,那么这个数就是一个重复值。转到下一个数,遍历一遍,后在遍历一遍,看与标号不相等的数,把这个数写入输出即可。

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

思路2:将当前数指向的那个数变成负数,如果后面出现它指向的数已经是负数了,那么这个数就是重复的数。这个只需要一次循环
public class Solution {
// when find a number i, flip the number at position i-1 to negative.
// if the number at position i-1 is already negative, i is the number that occurs twice.

public List<Integer> findDuplicates(int[] nums) {
List<Integer> res = new ArrayList<>();
for (int i = 0; i < nums.length; ++i) {
int index = Math.abs(nums[i])-1;
if (nums[index] < 0)
res.add(Math.abs(index+1));
nums[index] = -nums[index];
}
return res;
}
}



3 287. Find the Duplicate Number  只有一个重复的数出现

n+1个数,在1-n范围的数组内找到重复的那个数,这里面只有一个重复的数,重复的次数不限制。
要求:不能改变数字,空间复杂度是1,时间复杂度是n^2

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number,
find the duplicate one.

Note:

You must not modify the array (assume the array is read only).
You must use only constant, O(1) extra space.
Your runtime complexity should be less than 
O(n2)
.
There is only one duplicate number in the array, but it could be repeated more than once.

思路1:O(n)和O(1)空间
类似环状链表,重复的数字指向的同一个位置,当遇到第二个重复的数字时,又回到初始的地方,而第二个重复的数字就是这个环的入口。
设置快慢指针,第一次相遇时,将快指针指向初始位置,两个指针再次相遇时的位置就是重复的数字。

找含单链表的环入口点(转网上某位高手的解法)

class Solution {
public:
int findDuplicate(vector<int>& nums) {
int n=nums.size();
int slow=nums[0];
int fast=nums[slow];
if(nums.size()<=1) return -1;
while(slow!=fast)
{
slow=nums[slow];
fast=nums[nums[fast]];
}
fast=0;
while(slow!=fast)
{
slow=nums[slow];
fast=nums[fast];
}
return slow;
}
};


思路2:抽屉原理
选择中间的位置的数,统计他前面的数小于这个数的数量,如果大于中间位置标号,说明
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: