题目:在一个长度为 n 的数组里的全部数字都在 0 到 n-1 的范围内。
数组中某些数字是反复的,但不知道有几个数字反复了。也不知道每一个数字反复的次数。请找出数组中随意一个反复的数字。
比如假设输入长度为 7 的数组 {2,3,1,0,2,5,3}, 那么相应的输出是反复的数字 2 或者 3.
解决问题的一个简单的方法是先把输入的数组排序。从排序的数组中找出反复的数字是件 easy 的事情,仅仅须要从头到尾扫描排序后的数组就能够了。排序一个长度为 n 的数组须要时间为 O(nlogn) 时间。
还能够利用哈希表来解决问题。从头到尾按顺序扫描数组中的每一个数。每扫描到一个数字的时候,都能够用 O(1) 的时间来推断哈希表里是否已经包括了该数字。假设哈希表里没有这个数字。就把它增加到哈希表里。
假设哈希表里已经存在该数字了,那么就找到一个反复的数字。
这个算法的时间复杂度为 O(n),但它提高了时间复杂度是一个大小为 O(n) 的哈希表为代价的。我们再看看有没有时间复杂度为 O(1) 的算法。
我们注意到数组中的数字都在 0 到 n-1 的范围内的。假设这个数组中没有反复的数字。那么当数组排序后数字 i 将出如今下标为 i 的位置。因为数组中有反复的数字。有些位置可能存在数字,同一时候有些位置可能没有数字。
如今让我们重排这个数组。
从头到尾稻苗这个数组中的每一个数字。当扫描到下标为 i 的数字的时候。首先比較这个数字 (用 m 表示)是不是 i。假设是,接着扫描下一个数字。
假设不是,再拿它和第 m 个数字进行比較。
假设它和第 m 个数字相等。就找到一个反复的数字(该数字在下标为 i 和 m 的位置都出现了)。假设它和第 m 个数字不想等,就把第 i 个数字和第 m 个数字交换,把 m 放到属于它的位置。接下来再反复这个比較。交换的过程。直到发现一个反复的数字。
以数组{2,3,1,0,2,5,3}为例来分析找到反复数字的步骤。
数组的第 0 个数字(从 0 開始计数,和数组的下标保持一致)是 2,与它的下标不想等,于是把它和下标为 2 的数字 1 交换。交换后的数组是{1,3,2,0,2,5,3}。此时第 0 个数字是 1,仍然与它的下标不想等,继续把它和下标为 1 的数字 3 交换,得到数组{0。1。2。3,2,5,3}。此时第 0 个数字为 0。接着扫描下一个数字,在接下来的几个数字中。下标为 1。2。3 的三个数字分别为 1。2,3,他们的下标和数值都分别相等,因此不须要做不论什么操作。接下来扫描下标为 4 的数字 2. 因为它的值与它的下标不登,再比較它和下标为 2 的数字。
注意到此时数组中下标为 2 的数字也是 2,也就是数字 2 和下标为 2 和下标 4 的两个位置了,因此找到一个反复的数字。
Java 代码实现例如以下:
- /**
- * 数组中反复的数字
- */
- package swordForOffer;
- /**
- * @author JInShuangQi
- *
- * 2015年8月12日
- */
- public class E51DuplicationInArray {
- public boolean duplicate(int[] arr) {
- if (arr == null || arr.length <= 0) {
- return false;
- }
- for (int i = 0; i < arr.length; i++) {
- if (arr[i] < 0 || arr[i] > arr.length - 1) return false;
- }
- for (int i = 0; i < arr.length; i++) {
- while (arr[i] != i) {
- if (arr[i] == arr[arr[i]]) {
- System.out.println(arr[i]);
- return true;
- } else {
- int temp = arr[i];
- arr[i] = arr[temp];
- arr[temp] = temp;
- }
- }
- }
- return false;
- }
- public static void main(String[] args) {
- int[] arr = {
- 2,
- 3,
- 1,
- 0,
- 2,
- 5,
- 3
- };
- E51DuplicationInArray test = new E51DuplicationInArray();
- System.out.println(test.duplicate(arr));
- }
- }
.
在代码中虽然有一两个反复现年换。但每一个数字最多仅仅要交换两次就能找到属于自己的位置,因此总的时间复杂度为 O(n),另外,全部的操作步骤都是在输入数组上进行。不须要额外的分配内存。因此空间复杂度为 O(1).
来源: http://www.bubuko.com/infodetail-2051330.html