Skip to content

Commit

Permalink
Merge pull request #582 from 0xff-dev/287
Browse files Browse the repository at this point in the history
Add solution and update readme for problem 287
  • Loading branch information
6boris authored Aug 22, 2023
2 parents e8c692a + bba8210 commit dce4b9a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 60 deletions.
64 changes: 10 additions & 54 deletions leetcode/201-300/0287.Find-the-Duplicate-Number/README.md
Original file line number Diff line number Diff line change
@@ -1,74 +1,30 @@
# [# [1. Add Sum][title]
# [287.Find the Duplicate Number][title]

## Description

给定一个数组 nums 包含 n + 1 个整数,每个整数在 1 到 n 之间,包括 1 和 n。现在假设数组中存在一个重复的数字,找到该重复的数字。
Given an array of integers `nums` containing `n + 1` integers where each integer is in the range `[1, n]` inclusive.

注意
不能修改数组元素,假设数组是只读的。
仅可以使用常数即O(1)O(1)的额外空间。
时间复杂度需要低于O(n2)O(n2)。
数组中仅有一个重复数字,但它可能重复超过1次。
There is only **one repeated number** in `nums`, return this repeated number.

You must solve the problem **without** modifying the array `nums` and uses only constant extra space.

**Example 1:**

```
Example 1:
Input: [1,3,4,2,2]
Input: nums = [1,3,4,2,2]
Output: 2
Example 2:
Input: [3,1,3,4,2]
Output: 3
```

**Tags:** Math, String

## 题意
> 这道题目主要应用了抽屉原理和分治的思想。
抽屉原理:n+1 个苹果放在 n 个抽屉里,那么至少有一个抽屉中会放两个苹果。

用在这个题目中就是,一共有 n+1 个数,每个数的取值范围是1到n,所以至少会有一个数出现两次。

然后我们采用分治的思想,将每个数的取值的区间[1, n]划分成[1, n/2][n/2+1, n]两个子区间,然后分别统计两个区间中数的个数。
注意这里的区间是指 数的取值范围,而不是 数组下标。

划分之后,左右两个区间里一定至少存在一个区间,区间中数的个数大于区间长度。
这个可以用反证法来说明:如果两个区间中数的个数都小于等于区间长度,那么整个区间中数的个数就小于等于n,和有n+1个数矛盾。

因此我们可以把问题划归到左右两个子区间中的一个,而且由于区间中数的个数大于区间长度,根据抽屉原理,在这个子区间中一定存在某个数出现了两次。

依次类推,每次我们可以把区间长度缩小一半,直到区间长度为1时,我们就找到了答案。

作者:extrovert
链接:https://www.acwing.com/solution/LeetCode/content/2814/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

- 复杂度分析
时间复杂度:每次会将区间长度缩小一半,一共会缩小 O(logn) 次。每次统计两个子区间中的数时需要遍历整个数组,时间复杂度是 O(n)。所以总时间复杂度是 O(nlogn)。
空间复杂度:代码中没有用到额外的数组,所以额外的空间复杂度是 O(1)。

## 题解

### 思路1
> 。。。。
```go
**Example 2:**

```

### 思路2
> 思路2
```go

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

## 结语

如果你同我一样热爱数据结构、算法、LeetCode,可以关注我 GitHub 上的 LeetCode 题解:[awesome-golang-algorithm][me]

[title]: https://leetcode.com/problems/two-sum/description/
[title]: https://leetcode.com/problems/find-the-duplicate-number
[me]: https://github.com/kylesliu/awesome-golang-algorithm
32 changes: 28 additions & 4 deletions leetcode/201-300/0287.Find-the-Duplicate-Number/Solution.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"sort"
)

// 二分
// 二分
func findDuplicate(nums []int) int {
left, right := 0, len(nums)-1
for left < right {
Expand All @@ -25,7 +25,7 @@ func findDuplicate(nums []int) int {
return left
}

// 排序
// 排序
func findDuplicate2(nums []int) int {
sort.Ints(nums)
for i := 1; i < len(nums); i++ {
Expand All @@ -36,7 +36,7 @@ func findDuplicate2(nums []int) int {
return 0
}

// map
// map
func findDuplicate3(nums []int) int {
found := -1
m := make(map[int]int)
Expand All @@ -50,7 +50,7 @@ func findDuplicate3(nums []int) int {
return found
}

// 排序
// 排序
func findDuplicate4(nums []int) int {
for i := range nums {
tmp := int(math.Abs(float64(nums[i])))
Expand All @@ -61,3 +61,27 @@ func findDuplicate4(nums []int) int {
}
return -1
}

func findDuplicate5(nums []int) int {
ans := -1
for idx := range nums {
x := nums[idx]
if x < 0 {
x = -x
}
index := x - 1
r := nums[index]
if r < 0 {
ans = x
break
}

nums[index] = -nums[index]
}
for idx := range nums {
if nums[idx] < 0 {
nums[idx] = -nums[idx]
}
}
return ans
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,19 @@ func TestSolution(t *testing.T) {
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
c.expect, got, c.inputs)
}
got = findDuplicate5(c.inputs)
if !reflect.DeepEqual(got, c.expect) {
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
c.expect, got, c.inputs)
}
})
}
}

// 压力测试
// 压力测试
func BenchmarkSolution(b *testing.B) {
}

// 使用案列
// 使用案列
func ExampleSolution() {
}

0 comments on commit dce4b9a

Please sign in to comment.