287. 寻找重复数

这题的难点就在于下面的说明了,我们先不管下面的那些说明的要求,用常规的解法来解答下上的题目。

排序思想解法

先把原来的数组进行排序,然后逐个遍历,一旦发现后一个元素和当前的元素相等,那么就返回,这就是我们找到了重复数字。但是这种思想,就不满足说明里面的,不能改变原数组,虽然时间复杂度是满足O(n^2)。

哈希思想

用个哈希集合(HashSet)来记录已经出现过的元素,一旦遍历到了元素曾经出现在集合当中,那么就返回,这就是需要寻找的重复数字。

重新排序的思想

这种思想说起来有点复杂,但是时间复杂度是最好的。

我们从头开始遍历数组,遍历到的下标为i,那么我们就分两种情况来讨论:

  1. 如果num[i]等于(i+1),就是值等于刚好等于下标那么就遍历到下一个。因为刚刚好这个就是对应的,我们就不管他了。
  2. 如果num[i]和(i+1)不等,那么就去吧下标等于(num[i] - 1)的数字和这个数字进行交换(下标为i),这样再去判断如今的这个位置上的value和index是否相等,如果不等,继续交换。交换到这个位置上的num[i]和(i+1)相等为止;或者你会找到一个数字,这个数字,那个数字在对应的位置上已经有了,那么这个就是重复的那个数字了。

Talk is cheap, show me the code.

public int findDuplicate(int[] nums) {
if (nums.length == 0) {
return 0;
}
int res = 0;
for (int i = 0, len = nums.length; i < len; i++) {
int temp = i + 1;
// 判断num[i]的值是不是就是放在这
if (temp == nums[i]) {
continue;
} else {
// 两个不相同就进入循环,
while (temp != nums [i]) {
int newIndex = nums[i] - 1;
// 如果位置上的数字和num[i]相等,那么就表示出现重复的数字,
if (nums[newIndex] == nums[i]) {
return nums[i];
}
// 交换两个元素
int swapTemp = nums[newIndex];
nums[newIndex] = nums[i];
nums[i] = swapTemp;
}
}
}
return res;
}

当然了,以上依然不是最好的解法。因为虽然时间是O(n),但是却把原来的数组变动了。

用二分思想

这里的思想有点复杂,大概的思想是这样:

我们先假设一个如果排序好的数组中,你如果取中间的数字,那么如果你的这个中间数 是要比当前的索引的坐标大的话,那么就是也就是nums[i] > i,那么就是说明那个重复的数字是在后半部分的,因为只有在后半部分有重复数字存在的时候,才会多出一个数字来,那么我们就用二分法,吧start取到中点位置,继续寻找;反之,那个重复的数字是在前半部的。

因为我们这数组是没排序的数组,那么我们根据上面的那个计数的思想,我们先取一个取值范围,如果数组里面的元素的取值在这个取值范围的元素个数,等于这个取值范围的区间,那么就表示这个取值范围内不存在重复元素,我们要取别的区间的,继续计数。

public int findDuplicateNew(int[] nums) {
int start = 1;
int end = nums.length;
while (start <= end) {
// 取中值
int middle = start + ((end - start) >> 1);
// 计算从开始值到中值区间内有多少数字。
int tempCount = countRange(nums, start, middle);
// 如果已经区间已经缩小的到了只有一个数了,那么就可以判断在区间内的数字是不是有两个了。
if (start == end) {
if (tempCount > 1) {
return start;
} else {
break;
}
} // 区间就是 中值- 开始值 + 1。然后开始和计数比较。
int range = middle - start + 1;
if (tempCount > range) {
end = middle;
} else if (tempCount <= range) {
start = middle + 1;
}
}
return -1;
} // 计数比较,时间复杂度为O(n)
private int countRange(int[] nums, int start, int end) {
int count = 0;
for (int item : nums) {
if (item >= start && item <= end ) {
count++;
}
}
return count;
}

以上的时间复杂度是$O(NlogN)$ ,二分的时间复杂度是$O(logN)$,每次计数的时间复杂度是$O(N)$。

287. 寻找重复数 Java解法的更多相关文章

  1. leetcode.数组.287寻找重复数-Java

    1. 具体题目 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 1: ...

  2. Java实现 LeetCode 287 寻找重复数

    287. 寻找重复数 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 ...

  3. Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number)

    Leetcode之二分法专题-287. 寻找重复数(Find the Duplicate Number) 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和  ...

  4. 【Leetcode】287. 寻找重复数(数组模拟链表的快慢指针法)

    寻找重复数 根据题意,数组中的数字都在1~n之间,所以数字的范围是小于数组的范围的,数组的元素可以和数组的索引相联系. 例如:nums[0] = 1 即可以将nums[0]作为索引 通过nums[0] ...

  5. leetcode 287寻找重复数

    这道题用STL容器就很好写了,可以用set也可以用map, 用unordered_map的C++代码如下: class Solution { public: int findDuplicate(vec ...

  6. Leetcode题目287.寻找重复数(中等)

    题目描述: 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 1: 输入 ...

  7. 【leetcode】287. 寻找重复数

    题目链接:传送门 题目描述: 给定一个数组 nums 包含 n + 1 个整数,每个整数在 1 到 n 之间,包括 1 和 n.现在假设数组中存在一个重复的数字,找到该重复的数字. 注意 不能修改数组 ...

  8. LeetCode | 287. 寻找重复数

    特别感谢LeetCode大佬陈牧远的科普知识 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找 ...

  9. [LeetCode]287. 寻找重复数(二分)

    题目 给定一个包含 n + 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数.假设只有一个重复的整数,找出这个重复的数. 示例 1: 输入: [ ...

随机推荐

  1. Python基础(六) 函数

    .函数 函数是对动作的封装 2.1函数的基本结构 #函数的定义 def 函数名(): #函数提 pass #函数的执行 函数名() 2.2参数初识 #形参 def hanshu(aaa): #参数相当 ...

  2. 如何理解<T extends Comparable<? super T>>

    在看java容器类的时候经常可以看到<T extends Comparable<? super T>>,感觉十分不解? 我们觉得<T extends Comparable ...

  3. java关键字-interface

    1:是用关键字interface定义的. 2:接口中包含的成员,最常见的有全局常量.抽象方法. 注意:接口中的成员都有固定的修饰符. 成员变量:public static final 成员方法:pub ...

  4. 记录 nginx和php安装完后的URL重写,访问空白和隐藏index.php文件的操作方法

    sudo cd /etc/nginx/; sudo vi fastcgi_params; 1.URL重写 如果你的url参数不是用?xxx传递,而是自定义的,比如用/xx/xx/xx的方式传递,那么在 ...

  5. Java系统架构师学习体系图

  6. 移动IM开发指南1:如何进行技术选型

    <移动IM开发指南>系列文章将会介绍一个IM APP的方方面面,包括技术选型.登陆优化等.此外,本文作者会结合他在网易云信多年iOS IM SDK开发的经验,深度分析实际开发中的各种常见问 ...

  7. 【简单脚本】Linux查看配置信息

    命令比较多,统一整合了一下: 1.新建文件touch getComputerConf.sh 2.vim getComputerConf.sh 3.按i键插入,右键粘贴如下内容: #!/bin/sh e ...

  8. maven的下载与安装,卸载替换eclipse自带的maven

    首先呢,博主在这里给大家一个建议,最好不要用eclipse自带的maven.因为这家伙总会出现一些这样那样的错误,比如常见的jar包下载不全或者是install打包报错等等. 博主用了一段时间,还是觉 ...

  9. JVM史上最全实践优化没有之一

    JVM史上最全优化没有之一 1.jvm的运行参数 1.1 三种参数类型 1.1.1 -server与-clinet参数 2.1 -X参数 2.1.1 -Xint.-Xcomp.-Xmixed 3.1 ...

  10. .NET Core IdentityServer4实战 第Ⅴ章-单点登录

    OiDc可以说是OAuth的改造版,在最初的OAuth中,我们需要先请求一下认证服务器获取下Access_token,然后根据Access_token去Get资源服务器, 况且OAuth1 和 2 完 ...