剑指offer-数组-找出数组中重复的数字

剑指offer-数组-找出数组中重复的数字

1. 题目描述

给定一个长度为 n 的整数数组 nums,数组中所有的数字都在 0∼n−1 的范围内。

数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。

请找出数组中任意一个重复的数字。

注意:如果某些数字不在 0∼n−1 的范围内,或数组中不包含重复数字,则返回 -1;

样例
给定 nums = [2, 3, 5, 4, 3, 2, 6, 7]。

返回 2 或 3。

oj地址:https://www.acwing.com/problem/content/14/

2. 思路

观察数据特征发现,有重复的数字或没有重复数字,且数字的范围在【0,n-1】中(特例不在【0,n-1】再特殊处理)。那问题来了,如何利用上面特征快速的发现重复的数字?
利用数组中数字范围在【0,n-1】可以这样做,因为数组下标也是【0,n-1】,所以可将每个下标i上的数nums[i],放到nums[i]对应的下标nums[i]上,即设nums[i] = x,nums[x] = y,就是把x放在nums[x]上。至于如何放?是用交换方式,nums[i] <=>nums[x] ;交换完后 ,nums[i] = y,nums[x] = x,(可看出交换后y可能等于i,也可不等于所以i上新来的y是未知的,下面主要是依据它来判断是否重复)至此我把数字x放在了它对应的下标中,对于交换后i上的数y,继续重复把y放在到nums[y]上,若nums[y]已经是有nums[y]== y,那i上的y就是重复的并y一定是不等i的(现在出现了两个y,一个在对应自己下标y上,那另一个y绝对不在对应自己的位置上咯,数组下标是唯一的)。
所以继续将nums[i]上的数一直放在它的下标的循环条件是nums[nums[i]] != nums[i] (也就是nums[y]!= y) ,循环完后判断y是否是等于i,不等于i说明是重复的是y,等于说明y正好在自己位置上。

class Solution {
    public int duplicateInArray(int[] nums) {
        int n = nums.length;
        for(int i : nums){
            if(i <0 || i >= n)
            return -1;
        }
        for(int i=0;i<n;i++){
           
            while(nums[nums[i]] != nums[i]) {
                swap(nums, i, nums[i]);
            }
            
            if(nums[i] != i)
            return nums[i];
        }
       
        
        return -1;
    }
    void swap(int[] arr, int x,int y){
        int t = arr[x];
        arr[x] = arr[y];
       arr[y] =  t ;
    }
}

你可能感兴趣的:(算法)