3-LeetCode剑指 Offer 03. 数组中重复的数字

230 阅读1分钟

一、题目

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

样例1:

输入:
[2, 3, 1, 0, 2, 5, 3]

输出: 23 

限制:

2 <= n <= 100000

二、题解

废话不多说了,直接开始说方法

1. 使用set:循环遍历这个数组nums,直接用一个set来存储已经出现过的数据,用set中的has方法判断数字是否存在于set中,存在则返回该数字,不存在则将其用set中的add方法将其存进set.

1.2 使用set2:和方法1类似,也是用set,但是使用set中add前后的size值来判断(如果add之后size没变化,说明添加的数字set中已有,也就是重复数字,则返回该数字即可),会简单一些,思路是没问题的,本地样没问题,leetcode上一直报错,不知道为啥(这里是利用了set中不会添加重复值的性质)。

2.排序法:先对这个数组排序,然后分别判断这个数组的两个相邻元素是否相等,存在相等则是存在重复的数字.

3.原地交换法:利用“在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内”这个条件做文章,判断nums[i]是否等于i,如果等于则continue,然后判断num[nums[i]]和nums[i]是否相等,相等则代表存在相同的元素,这个时候return nums[i]即可,不等于则将nums[nums[i]]和nums[i]置换一下(这一步的目的就是为了使得nums[i]=i的情况),

这方法看起来可能是一头雾水(我一开始也是这样的),所以我们来代入数据详细看一下:

比如说有一个数组为[2,3,1,0,2,5,3]

那么的它索引值和对应的值的关系就为:

索引0 1 2 3 4 5 6
数组的值2 3 1 0 2 5 3

所以根据这个算法,我们先判断0是否等于nums[0],显然0不等于2,

然后我们判断nums[nums[i]]是否等于nums[i],也就是nums[nums[0]]是否等于nums[0],也就是nums[2]是否等于2,显然1不等于2,所以我们要将nums[nums[i]]和nums[i]转换一下,所以转换之后,那么的它索引值和对应的值的关系就为:

索引0 1 2 3 4 5 6
数组的值1 3 2 0 2 5 3

所以经过几次上述转换我们可以得到:

索引0 1 2 3 4 5 6
数组的值0 1 2 3 2 5 3

这时候我们发现nums[4] == nums[nums[4]](也就是nums[i]=nums[nums[i]]) 都等于2,所以这个时候就可以判断是有了重复的数字了,直接返回nums[4]即可,也就可以得出重复数字为2

3.1.辅助数组法:.和3类似,同样利用了题目的条件,但是这个方法更好理解,直接用一个大小也为n的全0数组arr来表示nums[i]值的个数,每次循环的时候都arr[nums[i]]++,当arr[nums[i]]>1时,就代表出现了多个nums[i],也就是说明有了重复数字,直接返回nums[i]即可!

三、代码(js)

// 1.遍历这个数组,用一个set,判断数字是否存在于set中,存在则返回该数字,不存在则将其存进set



/**

 * @param {number[]} nums

 * @return {number}

 */

 let findRepeatNumber = function(nums) {

      let repetitionSet = new Set();

      //遍历nums数组

      for(let i = 0,len=nums.length; i < len; i++) {

          if(repetitionSet.has(nums[i])) return nums[i];

          repetitionSet.add(nums[i]);      

      }

      return -1;


};



// // 1.2 这种之间判断set.add的思路感觉能行!!!但是有bug!!!!!!!之后再看看

/**

 * @param {number[]} nums

 * @return {number}

 */


 let repetitionSet = new Set();

 let findRepeatNumber = function(nums) {

    //遍历nums数组

    for(let i = 0,len=nums.length; i < len; i++) {

    
        //如果add之后的set和原set size值相同,则代表有重复数字加进来了

        // 这里是利用了set中不会添加重复值的性质

        if( repetitionSet.size===repetitionSet.add(nums[i]).size)

        {
           return nums[i];  
        }
    }

    return -1;

};


//2.将这个数组排序,如果判断两个数组是否相等


/**

 * @param {number[]} nums

 * @return {number}

 */

 let findRepeatNumber = function(nums) {

    //对nums先进行排序,然后找相邻的数字是否相同 

    nums.sort()

    for(let i = 0,len = nums.length;i<len;i++)

    {

        if(nums[i]==nums[i+1])

        {

           return nums[i]

        }

    }

    return -1

};



//3.利用全题目的条件,将索引和函数值关联起来

/**

 * @param {number[]} nums

 * @return {number}

 */


 let findRepeatNumber = function(nums) {

    for(let i = 0,len = nums.length;i<len;i++)

    {

        if(nums[i]==i)

            continue;


        if(nums[i]==nums[nums[i]])

          return nums[i];



        //这里有个细节!!!!!不能如下这样写,因为第一行的nums[i]和第三行的nums[i]不是一个值!!!

        // let t = nums[i];

        // nums[i] = nums[nums[i]];

        // nums[nums[i]] = t;

        

        let t = nums[i];

        nums[i] = nums[t];

        nums[t] = t;


    }

    return -1

};



//3.1利用全题目的条件,将索引和函数值关联起来 相比于3 一个是在原数组上操作,一个多了一个辅助数组!

/**

 * @param {number[]} nums

 * @return {number}

 */



 let findRepeatNumber = function(nums) {

    let arr = new Array(nums.length).fill(0)

    for(let i = 0,len = nums.length;i<len;i++)

    {

        arr[nums[i]]++;

        if(arr[nums[i]]>1){

            return nums[i];

            break;

        }

    }

    return -1

};

四、拓展思考

这里就具体讲下方法3的代码交换nums[i]和nums[nums[i]]时为什么不能写成:

let t = nums[i];

nums[i] = nums[nums[i]];

nums[nums[i]] = t;

具体来看的话就是:在第二行的时候nums[i]已经被nums[nums[i]]给覆盖了,所以第三行的nums[nums[i]]已经不是我们所想的nums[nums[i]]了,而是nums[nums[nums[i]]]了,所以第三行我们必须要用t,因为t在第一行被赋值为nums[i]后就没有改变!!!所以可以写成:

let t = nums[i];

nums[i] = nums[nums[i]];

nums[t] = t;

为了美观,所以我们把第二行的nums[i]也换成t了,所以我们最终写成:

let t = nums[i];

nums[i] = nums[t];

nums[t] = t;

写博客真的蛮累的,希望自己能坚持下去吧,加油!

题目来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/sh…