LeetCode - Medium - 287

Output: 2

Example 2:

Input: nums = [3,1,3,4,2]

Output: 3

Example 3:

Input: nums = [1,1]

Output: 1

Example 4:

Input: nums = [1,1,2]

Output: 1

Constraints:

  • 2 <= n <= 3 * 10⁴

  • nums.length == n + 1

  • 1 <= nums[i] <= n

  • All the integers in nums appear only once except for precisely one integer which appears two or more times.

Analysis


方法一:归位法,遍历数组,将数值转移到与下标相等的位置,若发现该下标位置的数已有与下标相等的数,则返回该下标值。该法的副作用是修改了数组内容。


方法二:将该问题转换成Linked List Cycle II。在脑里,将数组转换成链表形式,也就是从下标0开始,下标为0的元素则是链表的头节点的值,接着头节点的值为下标,从数组得出下一节点的值,以此类推,最后会得出带有环的链表。这样方便理解,如符合题意要求的数组:

| 0 | 1 | 2 | 3 | 4 |

| — | — | — | — | — |

| 1 | 3 | 4 | 2 | 3 |

转换成的链表:

┌─────────┐

↓ |

1 -> 3 -> 2 -> 4

链表中环的入口节点的数值则是题目要求的重复值。接着快慢双指针求出这个值。


方法三:二分查找

At first the search space is numbers between 1 to n. Each time I select a number mid (which is the one in the middle) and count all the numbers equal to or less than mid. Then if the count is more than mid, the search space will be [1, mid] otherwise [mid+1, n]. I do this until search space is only one number.

Let’s say n=10 and I select mid=5. Then I count all the numbers in the array which are less than equal (<=) mid. If the there are more than 5 numbers and other are less than 5, then by Pigeonhole Principle (https://en.wikipedia.org/wiki/Pigeonhole_principle) one of them has occurred more than once. So I shrink the search space from [1,10] to [1,5] (count >= mid, the duplicate number is in [1,5]). Otherwise the duplicate number is in the second half so for the next step the search space would be [6, 10].

Submission


public class FindTheDuplicateNumber {

// 方法一:

public int findDuplicate1(int[] nums) {

for (int i = 0; i < nums.length; i++) {

int should = i + 1;

while (nums[i] != should) {

if (nums[i] == nums[nums[i] - 1]) {

return nums[i];

}

swap(nums, i, nums[i] - 1);

}

}

return -1;

}

private void swap(int[] nums, int index1, int index2) {

int temp = nums[index1];

nums[index1] = nums[index2];

nums[index2] = temp;

}

// 方法二

public int findDuplicate2(int[] nums) {

if (nums.length > 1) {

int slow = nums[0];

int fast = nums[nums[0]];

while (slow != fast) {

slow = nums[slow];

fast = nums[nums[fast]];

}

fast = 0;

while (fast != slow) {

fast = nums[fast];

slow = nums[slow];

}

return slow;

}

return -1;

}

// 方法三

public int findDuplicate3(int[] nums) {

int low = 1, high = nums.length - 1;

while (low < high) {

int mid = low + (high - low) / 2;

int cnt = 0;

for (int a : nums) {

if (a <= mid)

++cnt;

}

if (cnt <= mid)

low = mid + 1;

else

high = mid;

}

return low;

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值