热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

leetcode[数组、双指针、二分搜索]寻找重复数(287)

1、问题描述给定一个包含n1个整数的数组nums,其中,每个整数的取值范围为[1,n],根据鸽巢原理可知,至

1、问题描述

给定一个包含n+1个整数的数组nums,其中,每个整数的取值范围为[1,n],根据鸽巢原理可知,至少存在一个重复的整数。假设只有一个重复的数,找出这个数。

2、解题思路


  • 边界条件与特殊情况:(1)nums中整数的个数小于2;
  • 问题分析:以nums=[1,3,4,2,3]为例,索引index的范围是在[0,n],元素值value的范围是[1,n],想象一下,把数组看成一个链表,数组中每一个位置上的元素值作为下一个元素的索引,当有元素重复时,会得到下面这样的带有环的索引链表:
    在这里插入图片描述

indexvalue
01
13
24
32
43

  • 思路1:根据上面的分析,类比判断链表中是否存在环问题的解题思路,采用快慢指针来解决这个问题,整个思路分为两个步骤:
  • (1)检测环。具体地,快、慢指针fast、slow都从0开始,进行如下循环:slow每次进行一跳,而fast进行两跳,比如,一开始slow=i、fast=i,下一步中,slow=nums[i],而fast=nums[nums[i]]。当slow等于fast,循环停止,此时slow和fast都停在环上某个节点。
  • (2)找到环的入口。具体地,finder指针从0开始,slow从上一步中slow和fast在环中的相遇的开始,进行如下循环:slow和finder指针每次都进行一跳。当finder等于fast时,循环停止,此时finder指向的为环的入口。
  • 这里可能有点难理解的是:为什么finder和slow会在环的入口处相遇?我们可以证明一下:
  • 假设起点到环的入口处长度为m,环的周长为c,在检测环的过程中,快慢指针在环中相遇,此时,fast走了2n步,slow走了n步,根据以上假设可得出以下结论:
  • 由于两个指针在环中相遇,所以多走的n步一定是c的整数倍,即n%c=0;
  • fast和slow相遇时,slow在环中行走的距离是n-m,此时,若finder从起点开始,slow从相遇点开始,两者同步前进,每次一步,当finder走了m步到达环的入口处时,slow走了n-m+m=n步,而n又是c的整数倍,故两者会在环的入口相遇。
  • 先声明一下数据结构:
  • slow慢指针、fast快指针,finder指针。
  • 初始化,一开始slow和fast都为0,finder也为0
  • 处理逻辑: 检测环和找到环的入口。
  • 这个方法的时间复杂度为O(n)O(n)O(n),空间复杂度为O(1)O(1)O(1)
  • 思路2:一说到查找,且时间复杂度小于O(n2)O(n^2)O(n2),则可以尝试二分查找,二分查找的思路如下:
  • 由于数组的元素的取值范围在[1&#xff0c;n]&#xff0c;所以需要查找的数的区间也left&#61;1、right&#61;n&#xff0c;取该区间的中位数mid&#xff0c;统计数组中小于等于mid的元素个数count&#xff0c;如果count<&#61;mid&#xff0c;则说明重复的整数在[mid&#43;1&#xff0c;right]区间&#xff0c;否则在[left&#xff0c;mid]之间&#xff0c;如果left
  • 由于进行了lognlognlogn次查找&#xff0c;统计小于mid的元素个数count时间复杂度为O(n)O(n)O(n)&#xff0c;所以时间复杂度为O(nlogn)O(nlogn)O(nlogn)&#xff0c;空间复杂度为O(1)O(1)O(1)

3、代码实现

快慢指针实现&#xff1a;

class Solution {
public:int findDuplicate(vector<int>& nums) {if (nums.size() < 2){return 0;}int slow&#61;0;int fast &#61; 0;int finder &#61; 0;while(true){slow &#61; nums[slow];fast &#61; nums[nums[fast]];if(slow &#61;&#61; fast){break;}}while(true){slow &#61; nums[slow];finder &#61; nums[finder];if(slow &#61;&#61; finder){break;}}return finder;}
};

二分搜索实现&#xff1a;

class Solution {
public:int findDuplicate(vector<int>& nums) {if (nums.size() < 2){return 0;}int left &#61; 1;int right &#61; nums.size() - 1;while(left < right){int mid &#61; (left &#43; right) /2;int count &#61; countNums(nums,mid);if(count <&#61; mid){left &#61; mid &#43; 1;}else{right &#61; mid;}}return left;}int countNums(vector<int>& nums,int e){int count &#61; 0;for(int i&#61;0;i<nums.size();i&#43;&#43;){if(nums[i] <&#61; e){count &#43;&#43;;}}return count;}
};


推荐阅读
author-avatar
桃花岛的小米_992
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有