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

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

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++) {
            if(nums[i] > 0) res.push_back(i+1);
        }
        return res;
    }
};

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:

  1. You must not modify the array (assume the array is read only).
  2. You must use only constant, O(1) extra space.
  3. Your runtime complexity should be less than O(n2).
  4. 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:抽屉原理
选择中间的位置的数,统计他前面的数小于这个数的数量,如果大于中间位置标号,说明


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值