最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 剑指 Offer 03. 数组中重复的数字 | 刷题打卡

    正文概述 掘金(moonlightop)   2021-03-06   494

    题目描述

    • 难度:容易
    • 找出数组中重复的数字。
    • 在一个长度为 n 的数组 nums 里的所有数字都在0~n-1的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字
    • 示例
      输入:
      [2, 3, 1, 0, 2, 5, 3]
      输出:2 或 3 
    
    • 限制:2 <= n <= 100000

    思路分析

    蛮力算法

    • 用两个for循环暴力遍历,比较第i个数字与i后面的数字是否相等,如果相等则找到了一个重复的数字并返回它,不等则i++,直到结束。(i初始为0)。
    • 显然,这样将要花费O(n^2)的时间复杂度,O(1)的空间复杂度。这样的时间复杂度实在太高,因此需要想办法去降低时间复杂度。

    快排 + 遍历

    • 先用快排将数组排序,然后再遍历数组对比第i和第i+1是否相等,如果相等则找到了一个重复的数字并返回,不等则i++,直到结束。(i初始为0)。
    • 通过快排来降低时间复杂度,O(nlogn + n) => O(nlogn)(大O表示法),空间复杂度为O(1)。

    空间换时间

    • 其实看到这道题目时,我最先回想起的是JavaScript中的深克隆的实现方法,可以先通过建立一个空对象(哈希表),然后遍历数组,若此对象(哈希表)没有当前数组元素,则将它添加进对象中,如果存在,则找到了一个重复的数字并返回。
    • 通过这样用空间换取时间的方法使得,时间复杂度变为O(n),而空间复杂度为O(n)。
    • 深克隆实现方式
      // *自定义函数实现深克隆
      var obj1 = {
        name: 'moonlightop',
        age: 20,
        sex: 'man',
        card: ['kai','chong']
      }
      var obj2 = {
        name: 'hao',
      }
    
      function DeepClone (Origin,Target) {
        // 将Origin克隆到Target中(object),返回深克隆好的对象Target
        Target = Target || {};
        // 遍历所有key - value,将它进行分为引用值和原始值
        for (var prop in Origin) {
    
          if (Origin.hasOwnProperty(prop)) {
            // typeof null -> object,需要排除它
            if (Origin[prop] !== null && typeof(Origin[prop]) === 'object') {
              // array object (typeof)
              if (Object.prototype.toString(Origin[prop]) === '[object object]') {
                // object
                Target[prop] = {};
              } else {
                // array
                Target[prop] = [];
              }
              DeepClone(Origin[prop],Target[prop]);
    
            } else {
              // number string function boolean null undefined
              Target[prop] = Origin[prop];
            }
          }
    
        }
    
        return Target;
    
      }
    
      DeepClone(obj1,obj2)
      obj2.card[2] = 'jian'
      console.log(obj2,obj1)
    

    原地置换(一个萝卜一个坑)

    • 我本以为已经没有更好的解法了,但一看题解发现,题目中还有一个条件没有使用起来,那就是数组的所有数字都在0~n-1的范围内,结合数组长度为n。
      • 我们完全没有必要新建一个对象或哈希表,直接在原数组中将nums[i]置换到第nums[i]中,通俗点说就是使得萝卜n放置回萝卜坑n中。但如果在将萝卜n放回到萝卜坑n时,发现萝卜坑n已经放有萝卜n,就说明找到了数组的一个重复的数字了。
           1. 初始开始遍历,填好一个坑才前进
               nums[i] 1 2 3 2 萝卜 
                  i    0 1 2 3 坑
           2. 发现0号坑中放的是1号萝卜,将它放回1号坑(即nums[i]与nums[nums[i]]交换)
               nums[i] 2 1 3 2 萝卜 
                  i    0 1 2 3 坑
           3. 0号坑放的是2号萝卜,同理将它放回2号坑
              nums[i] 3 1 2 2 萝卜 
                 i    0 1 2 3 坑
           4. 0号坑放的是3号萝卜,同理将它放回3号坑
           	 nums[i] 2 1 2 3 萝卜 
                 i    0 1 2 3 坑
           5. 0号坑放的是2号萝卜,将它放回2号坑时发现坑中已经有了2号萝卜,这样就找到了数组中的出现的重复数字2了
        
      • 这样就可以不需要额外的空间,时间复杂度依然为O(n)来解决这个问题了。

    AC代码

    /**
     * @param {number[]} nums
     * @return {number}
     */
    // 2. 先快速排序,再扫描数组 O(nlogn + n) = O(nlogn) 
    // function Divide (low,high,arr) {
    //     // console.log(arr,low,arr[low])
    //     var ref = arr[low];
    //     while (low < high) {
    //         while (low < high && arr[high] >= ref) 
    //             high --;
    //         arr[low] = arr[high];
    //         while (low < high && arr[low] <= ref)
    //             low ++;
    //         arr[high] = arr[low]
    //     }
    //     arr[low] = ref;
    //     return low;
    // }
    
    // function Qsort (low,high,arr) {
    //     if (low < high) {
    //         var divide = Divide(low,high,arr); 
    //         Qsort(low,divide - 1,arr);
    //         Qsort(divide + 1,high,arr);
    //     }
    // }
    
    
    var findRepeatNumber = function(nums) {
        // 1. 暴力解法 O(n^2)
        // for (var i = 0; i < nums.length - 1; i ++) {
        //     for (var j = i + 1; j < nums.length; j ++) {
        //         if (nums[i] === nums[j]) 
        //             return nums[i];
        //     }
        // }
    
        // 2. 先快速排序,再扫描数组 O(nlogn + n) = O(nlogn) 
        // Qsort (0,nums.length - 1,nums);
        // for (var i = 0; i < nums.length - 1; i ++) {
        //     if (nums[i] === nums[i + 1])
        //         return nums[i];
        // }
    
        // 3. 用空间换时间,建立一个对象(哈希表),扫描数组,检查当前的数组值是否已经存在数组(哈希表)
        //     O(n)
        // 对象版本
        // var newObj = {};
        // for (var i = 0; i < nums.length; i ++) {
        //     if (newObj.hasOwnProperty(nums[i])) {
        //         return nums[i]
        //     } else {
        //         newObj[ nums[i] ] = nums[i]
        //     }
        // }
    
        // 4. 扫描数组,使得nums[i] === i,而当nums[i] === nums[ nums[i] ]相等时就存在相同的数字
        //         O(n + k),k是指while循环的次数
        // for (var i = 0; i < nums.length; i ++) {
        //     while (nums[i] !== i) {
        //         if (nums[i] === nums[ nums[i] ]) {
        //             // 返回相同数字
        //             return nums[i];
        //         }
        //         // 交换 nums[i] 与 nums[ nums[i] ]
        //         var j = nums[i];
        //         nums[i] = nums[j];
        //         nums[j] = j;
        //     }
        // }
    
        var i = 0
        while (i < nums.length) {
            if (nums[i] !== i) {
                if (nums[i] === nums[ nums[i] ]) {
                    // 返回相同数字
                    return nums[i];
                }
                // 交换 nums[i] 与 nums[ nums[i] ]
                var j = nums[i];
                nums[i] = nums[j];
                nums[j] = j;
            } else {
                i ++
            }
        }
    
    };
    

    总结

    • 以前一直没有写题解的习惯,刷完题就算了,经过这一次的回顾,发现自己的题目的解法更加清晰,加深了自己的理解,加油!
    • 正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情

    起源地下载网 » 剑指 Offer 03. 数组中重复的数字 | 刷题打卡

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元