本文参考自《剑指offer》一书,代码采用Java语言。

更多:《剑指Offer》Java实现合集

题目 

  在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的数组。例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的输出是重复的数字2或者3。

思路

  数组长度为n+1,而数字只从1到n,说明必定有重复数字。可以由二分查找法拓展:把1~n的数字从中间数字m分成两部分,若前一半1~m的数字数目超过m个,说明重复数字在前一半区间,否则,在后半区间m+1~n。每次在区间中都一分为二,知道找到重复数字。

  更简单的思路:把该数组看作一个链表,下标代表当前结点,值代表next指针,具体参考Find the Duplicate Number,时间复杂度仅为O(n)

测试用例

  1.数组中带一个或多个重复数字

  2.数组中不包含重复的数字

  3.无效输入测试用例(空数组,数组数字越界等)

完整Java代码

(含测试代码)

/**
*
* @Description 不修改数组找出重复的数字
*
* @author yongh
* @date 2018年7月16日 上午11:47:44
*/ /*
* 题目:在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至
* 少有一个数字是重复的。请找出数组中任意一个重复的数字,但不能修改输入的
* 数组。例如,如果输入长度为8的数组{2, 3, 5, 4, 3, 2, 6, 7},那么对应的
* 输出是重复的数字2或者3。
*/
public class FindDuplication2 { /**
* 找到数组中一个重复的数字
* 返回-1代表无重复数字或者输入无效
*/
public int getDuplicate(int[] arr) {
if (arr == null || arr.length <= 0) {
System.out.println("数组输入无效!");
return -1;
}
for (int a : arr) {
if (a < 1 || a > arr.length - 1) {
System.out.println("数字大小超出范围!");
return -1;
}
}
int low = 1;
int high = arr.length - 1; // high即为题目的n
int mid, count;
while (low <= high) {
mid = ((high - low) >> 2) + low;
count = countRange(arr, low, mid);
if (low == high) {
if (count > 1)
return low;
else
break; // 必有重复,应该不会出现这种情况吧?
}
if (count > mid - low + 1) {
high = mid;
} else {
low = mid + 1;
}
}
return -1;
} /**
* 返回在[low,high]范围中数字的个数
*/
public int countRange(int[] arr, int low, int high) {
if (arr == null)
return 0; int count = 0;
for (int a : arr) {
if (a >= low && a <= high)
count++;
}
return count;
} // ==================================测试代码==================================
/**
*数组为null
*/
public void test1() {
System.out.print("test1:");
int[] a = null;
int dup = getDuplicate(a);
if (dup >= 0)
System.out.println("重复数字为:" + dup);
} /**
*数组数字越界
*/
public void test2() {
System.out.print("test2:");
int[] a = { 1, 2, 3, 4 };
int dup = getDuplicate(a);
if (dup >= 0)
System.out.println("重复数字为:" + dup);
} /**
*数组带重复数字
*/
public void test3() {
System.out.print("test3:");
int[] a = { 1, 2, 3, 2, 4 };
int dup = getDuplicate(a);
if (dup >= 0)
System.out.println("重复数字为:" + dup);
} public static void main(String[] args) {
FindDuplication2 f2 = new FindDuplication2();
f2.test1();
f2.test2();
f2.test3();
}
}

  

test1:数组输入无效!
test2:数字大小超出范围!
test3:重复数字为:2

FindDuplication2

复杂度

时间复杂度说明:函数countRange()将被调用O(logn)次,每次需要O(n)的时间。

时间复杂度:O(nlogn)  (while循环为O(logn),coutRange()函数为O(n))

空间复杂度:O(1)

更多:《剑指Offer》Java实现合集

【Java】 剑指offer(2) 不修改数组找出重复的数字的更多相关文章

  1. 一起来刷《剑指Offer》——不修改数组找出重复的数字(思路及Python实现)

    数组中重复的数字 在上一篇博客中<剑指Offer>-- 题目一:找出数组中重复的数字(Python多种方法实现)中,其实能发现这类题目的关键就是一边遍历数组一边查满足条件的元素. 然后我们 ...

  2. 《剑指offer》第三_二题(不修改数组找出重复的数字)

    // 面试题3(二):不修改数组找出重复的数字 // 题目:在一个长度为n+1的数组里的所有数字都在1到n的范围内,所以数组中至 // 少有一个数字是重复的.请找出数组中任意一个重复的数字,但不能修改 ...

  3. 【Offer】[3-2] 【不修改数组找出重复的数字】

    题目描述 思路分析 Java代码 代码链接 题目描述 在一个长度为n+1的数组里的所有数字都在1~n的范围内,所以数组中至少有一个数字是重复的. 请找出数组中任意一个重复的数字,但不能修改输入的数组. ...

  4. Acwing 14. 不修改数组找出重复的数字

    题目地址  https://www.acwing.com/problem/content/description/15/ 来源:剑指Offer 给定一个长度为 n+1n+1 的数组nums,数组中所有 ...

  5. 【剑指 Offer】03.1.不修改数组找出重复的数字

    找出数组中重复的数字. 在一个长度为 n + 1 的数组 nums 里的所有数字都在 1-n 的范围内.所以数组中至少有一个是重复的.请找出数组中任意一个重复的数字. 示例 1: 输入: [2, 3, ...

  6. 剑指offer笔记面试题3----数组中重复的数字

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

  7. 一起来刷《剑指Offer》-- 题目一:找出数组中重复的数字(Python多种方法实现)

    数组中重复的数字 最近在复习算法和数据结构(基于Python实现),然后看了Python的各种"序列"--比如列表List.元组Tuple和字符串String,后期会写一篇博客介绍 ...

  8. JS 剑指Offer(一) 数组中的重复数字

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

  9. 讲两个int 数组找出重复的数字 用最少的循环

    int a[] = {1,3}; int b[] = {1,3,5}; int size = a.length>b.length ?a.length:b.length; int valueA = ...

随机推荐

  1. php+mysql注入

    SQL简单命令介绍: mysql.exe -u 用户名  -p  密码  -h  ip地址 show databases;查看数据库 select version();php注入下的版本号 use d ...

  2. 20155237 2016-2017-2 《Java程序设计》第8周学习总结

    20155237 2016-2017-2 <Java程序设计>第8周学习总结 教材学习内容总结 NIO与NIO2 认识NIO Channel: 衔接数据节点(与IO中的流对比) isOpe ...

  3. PyCharm的调试

    1.设置断点 2.debug模式运行    F8      下一行代码 查看当前位置所有局部变量:print(locals()) 查看全局变量:                      print( ...

  4. luogu P1627 [CQOI2009]中位数

    传送门 要求有多少个长度为奇数的区间满足某个数为区间中位数 这样的区间,大于中位数的数个数 等于 小于中位数的数个数 用类似于前缀和的方法,设\(X_i\)为\(i\)和数\(b\)形成的区间内,大于 ...

  5. 下拉框combobox用法&级联餐单

    如果下来内容不用后台取数据,直接写死的话不用url属性,直接用data即可: <input id="orderstate" name="orderstate&quo ...

  6. python - 迭代器(迭代协议/可迭代对象)

    迭代器 # 迭代器协议 # 迭代协议:对象必须提供一个next方法,执行该方法要么返回迭代中的下一项,要么就触发一个 StopIteration 异常,以终止迭代(只能往后走不能往前退) # 可迭代对 ...

  7. 【转】CentOS 7.X 系统安装及优化

    [转]CentOS 7.X 系统安装及优化 centos的演变 启动流程sysvinit 串行启动:一次一个,一个一个启动 并行启动:全部的一起启动 init优点 运行非常良好.主要依赖于shell脚 ...

  8. Raw Socket vs Stream Socket vs datagram socket,原始套接字与流式套接字与数据报套接字

    https://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/ In this tutorial, let’s take a look ...

  9. 笔记软件 notion

    笔记软件 notion :     https://www.notion.so 注册:zengxinle@126.com     团队:Hopesun

  10. Python3学习笔记20-获取对象信息

    当我们拿到一个对象的引用时,如何知道这个对象是什么类型.有哪些方法呢? 基本类型都可以用type()判断: print(type(123)) print(type('str')) print(type ...