-
Difficulty: Easy
-
Related Topics: Array, Two Pointers, Binary Search
-
Link: https://leetcode.com/problems/find-the-duplicate-number/
Description
Given an array of integers nums
containing n + 1
integers where each integer is in the range [1, n]
inclusive.
给定一个包含 n + 1
个范围在 [1, n]
的整数的整数数组 nums
。
There is only one duplicate number in nums
, return this duplicate number.
数组里只存在一个重复的数字,找出这个重复的数字。
Follow up
-
How can we prove that at least one duplicate number must exists in
nums
?
如何证明nums
内一定存在至少 1 个重复的数字? -
Can you solve the problem without modifying the array
nums
?
你能在不修改nums
的情况下解答此问题吗? -
Can you solve the problem using only constant,
O(1)
extra space?
你能在 (O(1)) 空间复杂度内解答此问题吗? -
Can you solve the problem with runtime complexity less than
O(n^2)
?
你能在小于 (O(N^2)) 时间复杂度内解答此问题吗?
Examples
Example 1
Input: nums = [1,3,4,2,2]
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^4
-
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
Solution
感觉所有 Follow-up 里最好做到的是第 4 点,下面给出一个一般人都会想到的常规解法,时间复杂度 (O(N)),空间复杂度 (O(N)),不修改原数组:
class Solution {
fun findDuplicate(nums: IntArray): Int {
return nums.freq()
.filter { it.value > 1 }
.map { it.key }
.first()
}
private fun IntArray.freq(): Map<Int, Int> {
val result = hashMapOf<Int, Int>()
this.forEach { result[it] = result.getOrDefault(it, 0) + 1 }
return result
}
}
一开始看到这问题的时候,我首先想到的是之前做过的第 448 题. Find All Numbers Disappeared in an Array,但只是觉得有点像,但思路似乎不能通用,看了一眼 discussion 后茅塞顿开。要解答这个问题,我们不妨按以下规则遍历一遍数组:
-
起始状态是
nums[0]
。 -
以前一个数作为下标,取出
nums[prev]
作为下一个数。
因为题目规定数组长度是 n + 1
,所有数的范围是 [1, n]
,所以不用担心数组越界,将样例中的四个数组按如上方法遍历,得到以下结果:
[1,3,4,2,2] =>
1 -> 3 -> 2 -> 4 -> 2 -> 4 -> 2 -> 4 -> ...
[3,1,3,4,2] =>
3 -> 4 -> 2 -> 3 -> 4 -> 2 -> 3 -> 4 -> 2 -> ...
[1,1] =>
1 -> 1 -> 1 -> ...
[1,1,2] ->
1 -> 1 -> 1 -> ...
这不是成环链表遍历之后的形式吗?成环的那个节点即为所求。于是答案呼之欲出:参考成环链表找环的方法,无需修改原数组,时间复杂度 (O(N)),空间复杂度 (O(1)):
class Solution {
fun findDuplicate(nums: IntArray): Int {
// head = nums[0]
// fast = head.next.next
var fast = nums[nums[nums[0]]]
// slow = head.next
var slow = nums[nums[0]]
while (fast != slow) {
fast = nums[nums[fast]]
slow = nums[slow]
}
// 二者相遇,fast 移动回起点
fast = nums[0]
while (fast != slow) {
fast = nums[fast]
slow = nums[slow]
}
return slow
}
}