Skip to content

feat: add solutions to lc problem: No.0540 #3735

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
130 changes: 50 additions & 80 deletions solution/0500-0599/0540.Single Element in a Sorted Array/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,41 +58,15 @@ tags:

### 方法一:二分查找

给与的数组是有序的,由此可以使用二分查找,那条件该如何判断呢
题目给定的数组 $\textit{nums}$ 是有序的,且要求在 $\textit{O}(\log n)$ 时间找到只出现一次的元素,因此我们考虑使用二分查找解决

先观察一下线性遍历是如何确定目标的:
我们定义二分查找的左边界 $\textit{l} = 0$,右边界 $\textit{r} = n - 1$,其中 $n$ 是数组的长度。

```c
for (int i = 0; i < n - 1; i += 2) {
if (nums[i] != nums[i + 1]) {
return nums[i];
}
}
return nums[n - 1];
```
在每一步中,我们取中间位置 $\textit{mid} = (l + r) / 2$,如果下标 $\textit{mid}$ 为偶数,那么我们应该将 $\textit{nums}[\textit{mid}]$ 与 $\textit{nums}[\textit{mid} + 1]$ 进行比较;如果下标 $\textit{mid}$ 为奇数,那么我们应该将 $\textit{nums}[\textit{mid}]$ 与 $\textit{nums}[\textit{mid} - 1]$ 进行比较。因此,我们可以统一将 $\textit{nums}[\textit{mid}]$ 与 $\textit{nums}[\textit{mid} \oplus 1]$ 进行比较,其中 $\oplus$ 表示异或运算。

偶数下标:当 `nums[i] != nums[i + 1] && i % 2 == 0` 成立,结果便是 `nums[i]`。
奇数下标:当 `nums[i] != nums[i - 1] && i % 2 == 1` 成立,结果便是 `nums[i - 1]`。

于是二分模板就有了:

```txt
l = 0
r = n - 1
while l < r
m = l + (r - l) / 2
if m % 2 == 0
if nums[m] == nums[m + 1]
l = m + 1
else
r = m
else
if nums[m] == nums[m - 1]
l = m + 1
else
r = m
return nums[l]
```
如果 $\textit{nums}[\textit{mid}] \neq \textit{nums}[\textit{mid} \oplus 1]$,那么答案在 $[\textit{l}, \textit{mid}]$ 中,我们令 $\textit{r} = \textit{mid}$;如果 $\textit{nums}[\textit{mid}] = \textit{nums}[\textit{mid} \oplus 1]$,那么答案在 $[\textit{mid} + 1, \textit{r}]$ 中,我们令 $\textit{l} = \textit{mid} + 1$。继续二分查找,直到 $\textit{l} = \textit{r}$,此时 $\textit{nums}[\textit{l}]$ 即为只出现一次的元素。

时间复杂度 $\textit{O}(\log n)$,其中 $n$ 是数组 $\textit{nums}$ 的长度。空间复杂度 $\textit{O}(1)$。

<!-- tabs:start -->

Expand All @@ -101,34 +75,31 @@ return nums[l]
```python
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) >> 1
# Equals to: if (mid % 2 == 0 and nums[mid] != nums[mid + 1]) or (mid % 2 == 1 and nums[mid] != nums[mid - 1]):
l, r = 0, len(nums) - 1
while l < r:
mid = (l + r) >> 1
if nums[mid] != nums[mid ^ 1]:
right = mid
r = mid
else:
left = mid + 1
return nums[left]
l = mid + 1
return nums[l]
```

#### Java

```java
class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = (left + right) >> 1;
// if ((mid % 2 == 0 && nums[mid] != nums[mid + 1]) || (mid % 2 == 1 && nums[mid] !=
// nums[mid - 1])) {
int l = 0, r = nums.length - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
right = mid;
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
}
```
Expand All @@ -139,15 +110,16 @@ class Solution {
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + right >> 1;
if (nums[mid] != nums[mid ^ 1])
right = mid;
else
left = mid + 1;
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
r = mid;
} else {
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
};
```
Expand All @@ -156,34 +128,33 @@ public:

```go
func singleNonDuplicate(nums []int) int {
left, right := 0, len(nums)-1
for left < right {
mid := (left + right) >> 1
l, r := 0, len(nums)-1
for l < r {
mid := (l + r) >> 1
if nums[mid] != nums[mid^1] {
right = mid
r = mid
} else {
left = mid + 1
l = mid + 1
}
}
return nums[left]
return nums[l]
}
```

#### TypeScript

```ts
function singleNonDuplicate(nums: number[]): number {
let left = 0,
right = nums.length - 1;
while (left < right) {
const mid = (left + right) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
right = mid;
let [l, r] = [0, nums.length - 1];
while (l < r) {
const mid = (l + r) >> 1;
if (nums[mid] !== nums[mid ^ 1]) {
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
```

Expand All @@ -196,10 +167,10 @@ impl Solution {
let mut r = nums.len() - 1;
while l < r {
let mid = (l + r) >> 1;
if nums[mid] == nums[mid ^ 1] {
l = mid + 1;
} else {
if nums[mid] != nums[mid ^ 1] {
r = mid;
} else {
l = mid + 1;
}
}
nums[l]
Expand All @@ -211,17 +182,16 @@ impl Solution {

```c
int singleNonDuplicate(int* nums, int numsSize) {
int left = 0;
int right = numsSize - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == nums[mid ^ 1]) {
left = mid + 1;
int l = 0, r = numsSize - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
r = mid;
} else {
right = mid;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
```

Expand Down
104 changes: 55 additions & 49 deletions solution/0500-0599/0540.Single Element in a Sorted Array/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,17 @@ tags:

<!-- solution:start -->

### Solution 1
### Solution 1: Binary Search

The given array $\textit{nums}$ is sorted, and we need to find the element that appears only once in $\textit{O}(\log n)$ time. Therefore, we consider using binary search to solve this problem.

We define the left boundary of the binary search as $\textit{l} = 0$ and the right boundary as $\textit{r} = n - 1$, where $n$ is the length of the array.

In each step, we take the middle position $\textit{mid} = (l + r) / 2$. If the index $\textit{mid}$ is even, we should compare $\textit{nums}[\textit{mid}]$ with $\textit{nums}[\textit{mid} + 1]$. If the index $\textit{mid}$ is odd, we should compare $\textit{nums}[\textit{mid}]$ with $\textit{nums}[\textit{mid} - 1]$. Therefore, we can uniformly compare $\textit{nums}[\textit{mid}]$ with $\textit{nums}[\textit{mid} \oplus 1]$, where $\oplus$ denotes the XOR operation.

If $\textit{nums}[\textit{mid}] \neq \textit{nums}[\textit{mid} \oplus 1]$, then the answer is in $[\textit{l}, \textit{mid}]$, so we set $\textit{r} = \textit{mid}$. If $\textit{nums}[\textit{mid}] = \textit{nums}[\textit{mid} \oplus 1]$, then the answer is in $[\textit{mid} + 1, \textit{r}]$, so we set $\textit{l} = \textit{mid} + 1$. We continue the binary search until $\textit{l} = \textit{r}$, at which point $\textit{nums}[\textit{l}]$ is the element that appears only once.

The time complexity is $\textit{O}(\log n)$, where $n$ is the length of the array $\textit{nums}$. The space complexity is $\textit{O}(1)$.

<!-- tabs:start -->

Expand All @@ -54,34 +64,31 @@ tags:
```python
class Solution:
def singleNonDuplicate(self, nums: List[int]) -> int:
left, right = 0, len(nums) - 1
while left < right:
mid = (left + right) >> 1
# Equals to: if (mid % 2 == 0 and nums[mid] != nums[mid + 1]) or (mid % 2 == 1 and nums[mid] != nums[mid - 1]):
l, r = 0, len(nums) - 1
while l < r:
mid = (l + r) >> 1
if nums[mid] != nums[mid ^ 1]:
right = mid
r = mid
else:
left = mid + 1
return nums[left]
l = mid + 1
return nums[l]
```

#### Java

```java
class Solution {
public int singleNonDuplicate(int[] nums) {
int left = 0, right = nums.length - 1;
while (left < right) {
int mid = (left + right) >> 1;
// if ((mid % 2 == 0 && nums[mid] != nums[mid + 1]) || (mid % 2 == 1 && nums[mid] !=
// nums[mid - 1])) {
int l = 0, r = nums.length - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
right = mid;
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
}
```
Expand All @@ -92,15 +99,16 @@ class Solution {
class Solution {
public:
int singleNonDuplicate(vector<int>& nums) {
int left = 0, right = nums.size() - 1;
while (left < right) {
int mid = left + right >> 1;
if (nums[mid] != nums[mid ^ 1])
right = mid;
else
left = mid + 1;
int l = 0, r = nums.size() - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
r = mid;
} else {
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
};
```
Expand All @@ -109,34 +117,33 @@ public:

```go
func singleNonDuplicate(nums []int) int {
left, right := 0, len(nums)-1
for left < right {
mid := (left + right) >> 1
l, r := 0, len(nums)-1
for l < r {
mid := (l + r) >> 1
if nums[mid] != nums[mid^1] {
right = mid
r = mid
} else {
left = mid + 1
l = mid + 1
}
}
return nums[left]
return nums[l]
}
```

#### TypeScript

```ts
function singleNonDuplicate(nums: number[]): number {
let left = 0,
right = nums.length - 1;
while (left < right) {
const mid = (left + right) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
right = mid;
let [l, r] = [0, nums.length - 1];
while (l < r) {
const mid = (l + r) >> 1;
if (nums[mid] !== nums[mid ^ 1]) {
r = mid;
} else {
left = mid + 1;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
```

Expand All @@ -149,10 +156,10 @@ impl Solution {
let mut r = nums.len() - 1;
while l < r {
let mid = (l + r) >> 1;
if nums[mid] == nums[mid ^ 1] {
l = mid + 1;
} else {
if nums[mid] != nums[mid ^ 1] {
r = mid;
} else {
l = mid + 1;
}
}
nums[l]
Expand All @@ -164,17 +171,16 @@ impl Solution {

```c
int singleNonDuplicate(int* nums, int numsSize) {
int left = 0;
int right = numsSize - 1;
while (left < right) {
int mid = left + (right - left) / 2;
if (nums[mid] == nums[mid ^ 1]) {
left = mid + 1;
int l = 0, r = numsSize - 1;
while (l < r) {
int mid = (l + r) >> 1;
if (nums[mid] != nums[mid ^ 1]) {
r = mid;
} else {
right = mid;
l = mid + 1;
}
}
return nums[left];
return nums[l];
}
```

Expand Down
Loading
Loading