mirror of
https://github.com/krahets/hello-algo.git
synced 2026-08-18 22:40:59 +00:00
build
This commit is contained in:
+255
-255
@@ -51,26 +51,24 @@ comments: true
|
||||
|
||||
值得注意的是,由于 $i$ 和 $j$ 都是 `int` 类型,**因此 $i + j$ 可能会超出 `int` 类型的取值范围**。为了避免大数越界,我们通常采用公式 $m = \lfloor {i + (j - i) / 2} \rfloor$ 来计算中点。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search.java"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int[] nums, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = nums.length - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```python title="binary_search.py"
|
||||
def binary_search(nums: list[int], target: int) -> int:
|
||||
"""二分查找(双闭区间)"""
|
||||
# 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
i, j = 0, len(nums) - 1
|
||||
# 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while i <= j:
|
||||
# 理论上 Python 的数字可以无限大(取决于内存大小),无须考虑大数越界问题
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # 此情况说明 target 在区间 [i, m-1] 中
|
||||
else:
|
||||
return m # 找到目标元素,返回其索引
|
||||
return -1 # 未找到目标元素,返回 -1
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -95,24 +93,48 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search.py"
|
||||
def binary_search(nums: list[int], target: int) -> int:
|
||||
"""二分查找(双闭区间)"""
|
||||
# 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
i, j = 0, len(nums) - 1
|
||||
# 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while i <= j:
|
||||
# 理论上 Python 的数字可以无限大(取决于内存大小),无须考虑大数越界问题
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # 此情况说明 target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # 此情况说明 target 在区间 [i, m-1] 中
|
||||
else:
|
||||
return m # 找到目标元素,返回其索引
|
||||
return -1 # 未找到目标元素,返回 -1
|
||||
```java title="binary_search.java"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int[] nums, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = nums.length - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search.cs"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int[] nums, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = nums.Length - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -138,6 +160,30 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search.swift"
|
||||
/* 二分查找(双闭区间) */
|
||||
func binarySearch(nums: [Int], target: Int) -> Int {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
var i = 0
|
||||
var j = nums.count - 1
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1
|
||||
} else if nums[m] > target { // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return m
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search.js"
|
||||
@@ -190,98 +236,6 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search.c"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int *nums, int len, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = len - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search.cs"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int[] nums, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = nums.Length - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search.swift"
|
||||
/* 二分查找(双闭区间) */
|
||||
func binarySearch(nums: [Int], target: Int) -> Int {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
var i = 0
|
||||
var j = nums.count - 1
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target { // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1
|
||||
} else if nums[m] > target { // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return m
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search.zig"
|
||||
// 二分查找(双闭区间)
|
||||
fn binarySearch(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums.items[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search.dart"
|
||||
@@ -332,6 +286,52 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search.c"
|
||||
/* 二分查找(双闭区间) */
|
||||
int binarySearch(int *nums, int len, int target) {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
int i = 0, j = len - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search.zig"
|
||||
// 二分查找(双闭区间)
|
||||
fn binarySearch(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// 初始化双闭区间 [0, n-1] ,即 i, j 分别指向数组首元素、尾元素
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len - 1;
|
||||
// 循环,当搜索区间为空时跳出(当 i > j 时为空)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums.items[m] < target) { // 此情况说明 target 在区间 [m+1, j] 中
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // 此情况说明 target 在区间 [i, m-1] 中
|
||||
j = m - 1;
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
**时间复杂度 $O(\log n)$** :在二分循环中,区间每轮缩小一半,循环次数为 $\log_2 n$ 。
|
||||
|
||||
**空间复杂度 $O(1)$** :指针 $i$ 和 $j$ 使用常数大小空间。
|
||||
@@ -342,26 +342,23 @@ comments: true
|
||||
|
||||
我们可以基于该表示实现具有相同功能的二分查找算法。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search.java"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int[] nums, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = nums.length;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```python title="binary_search.py"
|
||||
def binary_search_lcro(nums: list[int], target: int) -> int:
|
||||
"""二分查找(左闭右开)"""
|
||||
# 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
i, j = 0, len(nums)
|
||||
# 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while i < j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # 此情况说明 target 在区间 [m+1, j) 中
|
||||
elif nums[m] > target:
|
||||
j = m # 此情况说明 target 在区间 [i, m) 中
|
||||
else:
|
||||
return m # 找到目标元素,返回其索引
|
||||
return -1 # 未找到目标元素,返回 -1
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -386,23 +383,48 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search.py"
|
||||
def binary_search_lcro(nums: list[int], target: int) -> int:
|
||||
"""二分查找(左闭右开)"""
|
||||
# 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
i, j = 0, len(nums)
|
||||
# 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while i < j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # 此情况说明 target 在区间 [m+1, j) 中
|
||||
elif nums[m] > target:
|
||||
j = m # 此情况说明 target 在区间 [i, m) 中
|
||||
else:
|
||||
return m # 找到目标元素,返回其索引
|
||||
return -1 # 未找到目标元素,返回 -1
|
||||
```java title="binary_search.java"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int[] nums, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = nums.length;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search.cs"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int[] nums, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = nums.Length;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -428,6 +450,30 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search.swift"
|
||||
/* 二分查找(左闭右开) */
|
||||
func binarySearchLCRO(nums: [Int], target: Int) -> Int {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
var i = 0
|
||||
var j = nums.count
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while i < j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1
|
||||
} else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return m
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search.js"
|
||||
@@ -481,98 +527,6 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search.c"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int *nums, int len, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = len;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search.cs"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int[] nums, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = nums.Length;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search.swift"
|
||||
/* 二分查找(左闭右开) */
|
||||
func binarySearchLCRO(nums: [Int], target: Int) -> Int {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
var i = 0
|
||||
var j = nums.count
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while i < j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target { // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1
|
||||
} else if nums[m] > target { // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return m
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search.zig"
|
||||
// 二分查找(左闭右开)
|
||||
fn binarySearchLCRO(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums.items[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search.dart"
|
||||
@@ -623,6 +577,52 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search.c"
|
||||
/* 二分查找(左闭右开) */
|
||||
int binarySearchLCRO(int *nums, int len, int target) {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
int i = 0, j = len;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i < j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
else if (nums[m] > target) // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
else // 找到目标元素,返回其索引
|
||||
return m;
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search.zig"
|
||||
// 二分查找(左闭右开)
|
||||
fn binarySearchLCRO(comptime T: type, nums: std.ArrayList(T), target: T) T {
|
||||
// 初始化左闭右开 [0, n) ,即 i, j 分别指向数组首元素、尾元素+1
|
||||
var i: usize = 0;
|
||||
var j: usize = nums.items.len;
|
||||
// 循环,当搜索区间为空时跳出(当 i = j 时为空)
|
||||
while (i <= j) {
|
||||
var m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums.items[m] < target) { // 此情况说明 target 在区间 [m+1, j) 中
|
||||
i = m + 1;
|
||||
} else if (nums.items[m] > target) { // 此情况说明 target 在区间 [i, m) 中
|
||||
j = m;
|
||||
} else { // 找到目标元素,返回其索引
|
||||
return @intCast(m);
|
||||
}
|
||||
}
|
||||
// 未找到目标元素,返回 -1
|
||||
return -1;
|
||||
}
|
||||
```
|
||||
|
||||
如图 10-3 所示,在两种区间表示下,二分查找算法的初始化、循环条件和缩小区间操作皆有所不同。
|
||||
|
||||
由于“双闭区间”表示中的左右边界都被定义为闭区间,因此指针 $i$ 和 $j$ 缩小区间操作也是对称的。这样更不容易出错,**因此一般建议采用“双闭区间”的写法**。
|
||||
|
||||
@@ -20,20 +20,18 @@ status: new
|
||||
|
||||
当遇到以上两种情况时,直接返回 $-1$ 即可。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search_edge.java"
|
||||
/* 二分查找最左一个 target */
|
||||
int binarySearchLeftEdge(int[] nums, int target) {
|
||||
// 等价于查找 target 的插入点
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target);
|
||||
// 未找到 target ,返回 -1
|
||||
if (i == nums.length || nums[i] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i;
|
||||
}
|
||||
```python title="binary_search_edge.py"
|
||||
def binary_search_left_edge(nums: list[int], target: int) -> int:
|
||||
"""二分查找最左一个 target"""
|
||||
# 等价于查找 target 的插入点
|
||||
i = binary_search_insertion(nums, target)
|
||||
# 未找到 target ,返回 -1
|
||||
if i == len(nums) or nums[i] != target:
|
||||
return -1
|
||||
# 找到 target ,返回索引 i
|
||||
return i
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -52,18 +50,36 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search_edge.py"
|
||||
def binary_search_left_edge(nums: list[int], target: int) -> int:
|
||||
"""二分查找最左一个 target"""
|
||||
# 等价于查找 target 的插入点
|
||||
i = binary_search_insertion(nums, target)
|
||||
# 未找到 target ,返回 -1
|
||||
if i == len(nums) or nums[i] != target:
|
||||
return -1
|
||||
# 找到 target ,返回索引 i
|
||||
return i
|
||||
```java title="binary_search_edge.java"
|
||||
/* 二分查找最左一个 target */
|
||||
int binarySearchLeftEdge(int[] nums, int target) {
|
||||
// 等价于查找 target 的插入点
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target);
|
||||
// 未找到 target ,返回 -1
|
||||
if (i == nums.length || nums[i] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_edge.cs"
|
||||
/* 二分查找最左一个 target */
|
||||
int binarySearchLeftEdge(int[] nums, int target) {
|
||||
// 等价于查找 target 的插入点
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target);
|
||||
// 未找到 target ,返回 -1
|
||||
if (i == nums.Length || nums[i] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -82,6 +98,22 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_edge.swift"
|
||||
/* 二分查找最左一个 target */
|
||||
func binarySearchLeftEdge(nums: [Int], target: Int) -> Int {
|
||||
// 等价于查找 target 的插入点
|
||||
let i = binarySearchInsertion(nums: nums, target: target)
|
||||
// 未找到 target ,返回 -1
|
||||
if i == nums.count || nums[i] != target {
|
||||
return -1
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search_edge.js"
|
||||
@@ -114,50 +146,6 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_edge.c"
|
||||
[class]{}-[func]{binarySearchLeftEdge}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_edge.cs"
|
||||
/* 二分查找最左一个 target */
|
||||
int binarySearchLeftEdge(int[] nums, int target) {
|
||||
// 等价于查找 target 的插入点
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target);
|
||||
// 未找到 target ,返回 -1
|
||||
if (i == nums.Length || nums[i] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_edge.swift"
|
||||
/* 二分查找最左一个 target */
|
||||
func binarySearchLeftEdge(nums: [Int], target: Int) -> Int {
|
||||
// 等价于查找 target 的插入点
|
||||
let i = binarySearchInsertion(nums: nums, target: target)
|
||||
// 未找到 target ,返回 -1
|
||||
if i == nums.count || nums[i] != target {
|
||||
return -1
|
||||
}
|
||||
// 找到 target ,返回索引 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_edge.zig"
|
||||
[class]{}-[func]{binarySearchLeftEdge}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search_edge.dart"
|
||||
@@ -190,6 +178,18 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_edge.c"
|
||||
[class]{}-[func]{binarySearchLeftEdge}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_edge.zig"
|
||||
[class]{}-[func]{binarySearchLeftEdge}
|
||||
```
|
||||
|
||||
## 10.3.2 查找右边界
|
||||
|
||||
那么如何查找最右一个 `target` 呢?最直接的方式是修改代码,替换在 `nums[m] == target` 情况下的指针收缩操作。代码在此省略,有兴趣的同学可以自行实现。
|
||||
@@ -208,22 +208,20 @@ status: new
|
||||
|
||||
请注意,返回的插入点是 $i$ ,因此需要将其减 $1$ ,从而获得 $j$ 。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search_edge.java"
|
||||
/* 二分查找最右一个 target */
|
||||
int binarySearchRightEdge(int[] nums, int target) {
|
||||
// 转化为查找最左一个 target + 1
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target + 1);
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
int j = i - 1;
|
||||
// 未找到 target ,返回 -1
|
||||
if (j == -1 || nums[j] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j;
|
||||
}
|
||||
```python title="binary_search_edge.py"
|
||||
def binary_search_right_edge(nums: list[int], target: int) -> int:
|
||||
"""二分查找最右一个 target"""
|
||||
# 转化为查找最左一个 target + 1
|
||||
i = binary_search_insertion(nums, target + 1)
|
||||
# j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
j = i - 1
|
||||
# 未找到 target ,返回 -1
|
||||
if j == -1 or nums[j] != target:
|
||||
return -1
|
||||
# 找到 target ,返回索引 j
|
||||
return j
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -244,20 +242,40 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search_edge.py"
|
||||
def binary_search_right_edge(nums: list[int], target: int) -> int:
|
||||
"""二分查找最右一个 target"""
|
||||
# 转化为查找最左一个 target + 1
|
||||
i = binary_search_insertion(nums, target + 1)
|
||||
# j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
j = i - 1
|
||||
# 未找到 target ,返回 -1
|
||||
if j == -1 or nums[j] != target:
|
||||
return -1
|
||||
# 找到 target ,返回索引 j
|
||||
return j
|
||||
```java title="binary_search_edge.java"
|
||||
/* 二分查找最右一个 target */
|
||||
int binarySearchRightEdge(int[] nums, int target) {
|
||||
// 转化为查找最左一个 target + 1
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target + 1);
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
int j = i - 1;
|
||||
// 未找到 target ,返回 -1
|
||||
if (j == -1 || nums[j] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_edge.cs"
|
||||
/* 二分查找最右一个 target */
|
||||
int binarySearchRightEdge(int[] nums, int target) {
|
||||
// 转化为查找最左一个 target + 1
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target + 1);
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
int j = i - 1;
|
||||
// 未找到 target ,返回 -1
|
||||
if (j == -1 || nums[j] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -278,6 +296,24 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_edge.swift"
|
||||
/* 二分查找最右一个 target */
|
||||
func binarySearchRightEdge(nums: [Int], target: Int) -> Int {
|
||||
// 转化为查找最左一个 target + 1
|
||||
let i = binarySearchInsertion(nums: nums, target: target + 1)
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
let j = i - 1
|
||||
// 未找到 target ,返回 -1
|
||||
if j == -1 || nums[j] != target {
|
||||
return -1
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search_edge.js"
|
||||
@@ -314,54 +350,6 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_edge.c"
|
||||
[class]{}-[func]{binarySearchRightEdge}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_edge.cs"
|
||||
/* 二分查找最右一个 target */
|
||||
int binarySearchRightEdge(int[] nums, int target) {
|
||||
// 转化为查找最左一个 target + 1
|
||||
int i = binary_search_insertion.binarySearchInsertion(nums, target + 1);
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
int j = i - 1;
|
||||
// 未找到 target ,返回 -1
|
||||
if (j == -1 || nums[j] != target) {
|
||||
return -1;
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_edge.swift"
|
||||
/* 二分查找最右一个 target */
|
||||
func binarySearchRightEdge(nums: [Int], target: Int) -> Int {
|
||||
// 转化为查找最左一个 target + 1
|
||||
let i = binarySearchInsertion(nums: nums, target: target + 1)
|
||||
// j 指向最右一个 target ,i 指向首个大于 target 的元素
|
||||
let j = i - 1
|
||||
// 未找到 target ,返回 -1
|
||||
if j == -1 || nums[j] != target {
|
||||
return -1
|
||||
}
|
||||
// 找到 target ,返回索引 j
|
||||
return j
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_edge.zig"
|
||||
[class]{}-[func]{binarySearchRightEdge}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search_edge.dart"
|
||||
@@ -398,6 +386,18 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_edge.c"
|
||||
[class]{}-[func]{binarySearchRightEdge}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_edge.zig"
|
||||
[class]{}-[func]{binarySearchRightEdge}
|
||||
```
|
||||
|
||||
### 2. 转化为查找元素
|
||||
|
||||
我们知道,当数组不包含 `target` 时,最终 $i$ 和 $j$ 会分别指向首个大于、小于 `target` 的元素。
|
||||
|
||||
@@ -29,25 +29,22 @@ status: new
|
||||
|
||||
因此二分结束时一定有:$i$ 指向首个大于 `target` 的元素,$j$ 指向首个小于 `target` 的元素。**易得当数组不包含 `target` 时,插入索引为 $i$** 。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search_insertion.java"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
int binarySearchInsertionSimple(int[] nums, int target) {
|
||||
int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m; // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```python title="binary_search_insertion.py"
|
||||
def binary_search_insertion_simple(nums: list[int], target: int) -> int:
|
||||
"""二分查找插入点(无重复元素)"""
|
||||
i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1]
|
||||
while i <= j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # target 在区间 [i, m-1] 中
|
||||
else:
|
||||
return m # 找到 target ,返回插入点 m
|
||||
# 未找到 target ,返回插入点 i
|
||||
return i
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -71,22 +68,46 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search_insertion.py"
|
||||
def binary_search_insertion_simple(nums: list[int], target: int) -> int:
|
||||
"""二分查找插入点(无重复元素)"""
|
||||
i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1]
|
||||
while i <= j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # target 在区间 [i, m-1] 中
|
||||
else:
|
||||
return m # 找到 target ,返回插入点 m
|
||||
# 未找到 target ,返回插入点 i
|
||||
return i
|
||||
```java title="binary_search_insertion.java"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
int binarySearchInsertionSimple(int[] nums, int target) {
|
||||
int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m; // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_insertion.cs"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
int binarySearchInsertionSimple(int[] nums, int target) {
|
||||
int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m; // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -115,6 +136,27 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_insertion.swift"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int {
|
||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target {
|
||||
i = m + 1 // target 在区间 [m+1, j] 中
|
||||
} else if nums[m] > target {
|
||||
j = m - 1 // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search_insertion.js"
|
||||
@@ -162,60 +204,6 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_insertion.c"
|
||||
[class]{}-[func]{binarySearchInsertionSimple}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_insertion.cs"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
int binarySearchInsertionSimple(int[] nums, int target) {
|
||||
int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m; // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_insertion.swift"
|
||||
/* 二分查找插入点(无重复元素) */
|
||||
func binarySearchInsertionSimple(nums: [Int], target: Int) -> Int {
|
||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target {
|
||||
i = m + 1 // target 在区间 [m+1, j] 中
|
||||
} else if nums[m] > target {
|
||||
j = m - 1 // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
return m // 找到 target ,返回插入点 m
|
||||
}
|
||||
}
|
||||
// 未找到 target ,返回插入点 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_insertion.zig"
|
||||
[class]{}-[func]{binarySearchInsertionSimple}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search_insertion.dart"
|
||||
@@ -258,6 +246,18 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_insertion.c"
|
||||
[class]{}-[func]{binarySearchInsertionSimple}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_insertion.zig"
|
||||
[class]{}-[func]{binarySearchInsertionSimple}
|
||||
```
|
||||
|
||||
## 10.2.2 存在重复元素的情况
|
||||
|
||||
!!! question
|
||||
@@ -314,25 +314,22 @@ status: new
|
||||
|
||||
即便如此,我们仍然可以将判断条件保持展开,因为其逻辑更加清晰、可读性更好。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="binary_search_insertion.java"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
int binarySearchInsertion(int[] nums, int target) {
|
||||
int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```python title="binary_search_insertion.py"
|
||||
def binary_search_insertion(nums: list[int], target: int) -> int:
|
||||
"""二分查找插入点(存在重复元素)"""
|
||||
i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1]
|
||||
while i <= j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # target 在区间 [i, m-1] 中
|
||||
else:
|
||||
j = m - 1 # 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
# 返回插入点 i
|
||||
return i
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -356,22 +353,46 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="binary_search_insertion.py"
|
||||
def binary_search_insertion(nums: list[int], target: int) -> int:
|
||||
"""二分查找插入点(存在重复元素)"""
|
||||
i, j = 0, len(nums) - 1 # 初始化双闭区间 [0, n-1]
|
||||
while i <= j:
|
||||
m = (i + j) // 2 # 计算中点索引 m
|
||||
if nums[m] < target:
|
||||
i = m + 1 # target 在区间 [m+1, j] 中
|
||||
elif nums[m] > target:
|
||||
j = m - 1 # target 在区间 [i, m-1] 中
|
||||
else:
|
||||
j = m - 1 # 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
# 返回插入点 i
|
||||
return i
|
||||
```java title="binary_search_insertion.java"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
int binarySearchInsertion(int[] nums, int target) {
|
||||
int i = 0, j = nums.length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_insertion.cs"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
int binarySearchInsertion(int[] nums, int target) {
|
||||
int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -400,6 +421,27 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_insertion.swift"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
func binarySearchInsertion(nums: [Int], target: Int) -> Int {
|
||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target {
|
||||
i = m + 1 // target 在区间 [m+1, j] 中
|
||||
} else if nums[m] > target {
|
||||
j = m - 1 // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1 // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="binary_search_insertion.js"
|
||||
@@ -444,60 +486,6 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_insertion.c"
|
||||
[class]{}-[func]{binarySearchInsertion}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="binary_search_insertion.cs"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
int binarySearchInsertion(int[] nums, int target) {
|
||||
int i = 0, j = nums.Length - 1; // 初始化双闭区间 [0, n-1]
|
||||
while (i <= j) {
|
||||
int m = i + (j - i) / 2; // 计算中点索引 m
|
||||
if (nums[m] < target) {
|
||||
i = m + 1; // target 在区间 [m+1, j] 中
|
||||
} else if (nums[m] > target) {
|
||||
j = m - 1; // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1; // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="binary_search_insertion.swift"
|
||||
/* 二分查找插入点(存在重复元素) */
|
||||
func binarySearchInsertion(nums: [Int], target: Int) -> Int {
|
||||
var i = 0, j = nums.count - 1 // 初始化双闭区间 [0, n-1]
|
||||
while i <= j {
|
||||
let m = i + (j - i) / 2 // 计算中点索引 m
|
||||
if nums[m] < target {
|
||||
i = m + 1 // target 在区间 [m+1, j] 中
|
||||
} else if nums[m] > target {
|
||||
j = m - 1 // target 在区间 [i, m-1] 中
|
||||
} else {
|
||||
j = m - 1 // 首个小于 target 的元素在区间 [i, m-1] 中
|
||||
}
|
||||
}
|
||||
// 返回插入点 i
|
||||
return i
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_insertion.zig"
|
||||
[class]{}-[func]{binarySearchInsertion}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="binary_search_insertion.dart"
|
||||
@@ -540,6 +528,18 @@ status: new
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="binary_search_insertion.c"
|
||||
[class]{}-[func]{binarySearchInsertion}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="binary_search_insertion.zig"
|
||||
[class]{}-[func]{binarySearchInsertion}
|
||||
```
|
||||
|
||||
!!! tip
|
||||
|
||||
本节的代码都是“双闭区间”写法。有兴趣的读者可以自行实现“左闭右开”写法。
|
||||
|
||||
@@ -18,21 +18,17 @@ comments: true
|
||||
|
||||
<p align="center"> 图 10-9 线性查找求解两数之和 </p>
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="two_sum.java"
|
||||
/* 方法一:暴力枚举 */
|
||||
int[] twoSumBruteForce(int[] nums, int target) {
|
||||
int size = nums.length;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
for (int j = i + 1; j < size; j++) {
|
||||
if (nums[i] + nums[j] == target)
|
||||
return new int[] { i, j };
|
||||
}
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
```python title="two_sum.py"
|
||||
def two_sum_brute_force(nums: list[int], target: int) -> list[int]:
|
||||
"""方法一:暴力枚举"""
|
||||
# 两层循环,时间复杂度 O(n^2)
|
||||
for i in range(len(nums) - 1):
|
||||
for j in range(i + 1, len(nums)):
|
||||
if nums[i] + nums[j] == target:
|
||||
return [i, j]
|
||||
return []
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -52,17 +48,38 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="two_sum.py"
|
||||
def two_sum_brute_force(nums: list[int], target: int) -> list[int]:
|
||||
"""方法一:暴力枚举"""
|
||||
# 两层循环,时间复杂度 O(n^2)
|
||||
for i in range(len(nums) - 1):
|
||||
for j in range(i + 1, len(nums)):
|
||||
if nums[i] + nums[j] == target:
|
||||
return [i, j]
|
||||
return []
|
||||
```java title="two_sum.java"
|
||||
/* 方法一:暴力枚举 */
|
||||
int[] twoSumBruteForce(int[] nums, int target) {
|
||||
int size = nums.length;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
for (int j = i + 1; j < size; j++) {
|
||||
if (nums[i] + nums[j] == target)
|
||||
return new int[] { i, j };
|
||||
}
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="two_sum.cs"
|
||||
/* 方法一:暴力枚举 */
|
||||
int[] twoSumBruteForce(int[] nums, int target) {
|
||||
int size = nums.Length;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
for (int j = i + 1; j < size; j++) {
|
||||
if (nums[i] + nums[j] == target)
|
||||
return new int[] { i, j };
|
||||
}
|
||||
}
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -83,6 +100,23 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="two_sum.swift"
|
||||
/* 方法一:暴力枚举 */
|
||||
func twoSumBruteForce(nums: [Int], target: Int) -> [Int] {
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for i in nums.indices.dropLast() {
|
||||
for j in nums.indices.dropFirst(i + 1) {
|
||||
if nums[i] + nums[j] == target {
|
||||
return [i, j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return [0]
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="two_sum.js"
|
||||
@@ -119,80 +153,6 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="two_sum.c"
|
||||
/* 方法一:暴力枚举 */
|
||||
int *twoSumBruteForce(int *nums, int numsSize, int target, int *returnSize) {
|
||||
for (int i = 0; i < numsSize; ++i) {
|
||||
for (int j = i + 1; j < numsSize; ++j) {
|
||||
if (nums[i] + nums[j] == target) {
|
||||
int *res = malloc(sizeof(int) * 2);
|
||||
res[0] = i, res[1] = j;
|
||||
*returnSize = 2;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
*returnSize = 0;
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="two_sum.cs"
|
||||
/* 方法一:暴力枚举 */
|
||||
int[] twoSumBruteForce(int[] nums, int target) {
|
||||
int size = nums.Length;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for (int i = 0; i < size - 1; i++) {
|
||||
for (int j = i + 1; j < size; j++) {
|
||||
if (nums[i] + nums[j] == target)
|
||||
return new int[] { i, j };
|
||||
}
|
||||
}
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="two_sum.swift"
|
||||
/* 方法一:暴力枚举 */
|
||||
func twoSumBruteForce(nums: [Int], target: Int) -> [Int] {
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
for i in nums.indices.dropLast() {
|
||||
for j in nums.indices.dropFirst(i + 1) {
|
||||
if nums[i] + nums[j] == target {
|
||||
return [i, j]
|
||||
}
|
||||
}
|
||||
}
|
||||
return [0]
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="two_sum.zig"
|
||||
// 方法一:暴力枚举
|
||||
fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 {
|
||||
var size: usize = nums.len;
|
||||
var i: usize = 0;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
while (i < size - 1) : (i += 1) {
|
||||
var j = i + 1;
|
||||
while (j < size) : (j += 1) {
|
||||
if (nums[i] + nums[j] == target) {
|
||||
return [_]i32{@intCast(i), @intCast(j)};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="two_sum.dart"
|
||||
@@ -227,6 +187,46 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="two_sum.c"
|
||||
/* 方法一:暴力枚举 */
|
||||
int *twoSumBruteForce(int *nums, int numsSize, int target, int *returnSize) {
|
||||
for (int i = 0; i < numsSize; ++i) {
|
||||
for (int j = i + 1; j < numsSize; ++j) {
|
||||
if (nums[i] + nums[j] == target) {
|
||||
int *res = malloc(sizeof(int) * 2);
|
||||
res[0] = i, res[1] = j;
|
||||
*returnSize = 2;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
*returnSize = 0;
|
||||
return NULL;
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="two_sum.zig"
|
||||
// 方法一:暴力枚举
|
||||
fn twoSumBruteForce(nums: []i32, target: i32) ?[2]i32 {
|
||||
var size: usize = nums.len;
|
||||
var i: usize = 0;
|
||||
// 两层循环,时间复杂度 O(n^2)
|
||||
while (i < size - 1) : (i += 1) {
|
||||
var j = i + 1;
|
||||
while (j < size) : (j += 1) {
|
||||
if (nums[i] + nums[j] == target) {
|
||||
return [_]i32{@intCast(i), @intCast(j)};
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
此方法的时间复杂度为 $O(n^2)$ ,空间复杂度为 $O(1)$ ,在大数据量下非常耗时。
|
||||
|
||||
## 10.4.2 哈希查找:以空间换时间
|
||||
@@ -249,23 +249,19 @@ comments: true
|
||||
|
||||
实现代码如下所示,仅需单层循环即可。
|
||||
|
||||
=== "Java"
|
||||
=== "Python"
|
||||
|
||||
```java title="two_sum.java"
|
||||
/* 方法二:辅助哈希表 */
|
||||
int[] twoSumHashTable(int[] nums, int target) {
|
||||
int size = nums.length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Map<Integer, Integer> dic = new HashMap<>();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (dic.containsKey(target - nums[i])) {
|
||||
return new int[] { dic.get(target - nums[i]), i };
|
||||
}
|
||||
dic.put(nums[i], i);
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
```python title="two_sum.py"
|
||||
def two_sum_hash_table(nums: list[int], target: int) -> list[int]:
|
||||
"""方法二:辅助哈希表"""
|
||||
# 辅助哈希表,空间复杂度 O(n)
|
||||
dic = {}
|
||||
# 单层循环,时间复杂度 O(n)
|
||||
for i in range(len(nums)):
|
||||
if target - nums[i] in dic:
|
||||
return [dic[target - nums[i]], i]
|
||||
dic[nums[i]] = i
|
||||
return []
|
||||
```
|
||||
|
||||
=== "C++"
|
||||
@@ -287,19 +283,42 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Python"
|
||||
=== "Java"
|
||||
|
||||
```python title="two_sum.py"
|
||||
def two_sum_hash_table(nums: list[int], target: int) -> list[int]:
|
||||
"""方法二:辅助哈希表"""
|
||||
# 辅助哈希表,空间复杂度 O(n)
|
||||
dic = {}
|
||||
# 单层循环,时间复杂度 O(n)
|
||||
for i in range(len(nums)):
|
||||
if target - nums[i] in dic:
|
||||
return [dic[target - nums[i]], i]
|
||||
dic[nums[i]] = i
|
||||
return []
|
||||
```java title="two_sum.java"
|
||||
/* 方法二:辅助哈希表 */
|
||||
int[] twoSumHashTable(int[] nums, int target) {
|
||||
int size = nums.length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Map<Integer, Integer> dic = new HashMap<>();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (dic.containsKey(target - nums[i])) {
|
||||
return new int[] { dic.get(target - nums[i]), i };
|
||||
}
|
||||
dic.put(nums[i], i);
|
||||
}
|
||||
return new int[0];
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="two_sum.cs"
|
||||
/* 方法二:辅助哈希表 */
|
||||
int[] twoSumHashTable(int[] nums, int target) {
|
||||
int size = nums.Length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Dictionary<int, int> dic = new();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (dic.ContainsKey(target - nums[i])) {
|
||||
return new int[] { dic[target - nums[i]], i };
|
||||
}
|
||||
dic.Add(nums[i], i);
|
||||
}
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
```
|
||||
|
||||
=== "Go"
|
||||
@@ -320,6 +339,24 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="two_sum.swift"
|
||||
/* 方法二:辅助哈希表 */
|
||||
func twoSumHashTable(nums: [Int], target: Int) -> [Int] {
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
var dic: [Int: Int] = [:]
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for i in nums.indices {
|
||||
if let j = dic[target - nums[i]] {
|
||||
return [j, i]
|
||||
}
|
||||
dic[nums[i]] = i
|
||||
}
|
||||
return [0]
|
||||
}
|
||||
```
|
||||
|
||||
=== "JS"
|
||||
|
||||
```javascript title="two_sum.js"
|
||||
@@ -359,6 +396,43 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="two_sum.dart"
|
||||
/* 方法二: 辅助哈希表 */
|
||||
List<int> twoSumHashTable(List<int> nums, int target) {
|
||||
int size = nums.length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Map<int, int> dic = HashMap();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (var i = 0; i < size; i++) {
|
||||
if (dic.containsKey(target - nums[i])) {
|
||||
return [dic[target - nums[i]]!, i];
|
||||
}
|
||||
dic.putIfAbsent(nums[i], () => i);
|
||||
}
|
||||
return [0];
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="two_sum.rs"
|
||||
/* 方法二:辅助哈希表 */
|
||||
pub fn two_sum_hash_table(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
let mut dic = HashMap::new();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (i, num) in nums.iter().enumerate() {
|
||||
match dic.get(&(target - num)) {
|
||||
Some(v) => return Some(vec![*v as i32, i as i32]),
|
||||
None => dic.insert(num, i as i32)
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
=== "C"
|
||||
|
||||
```c title="two_sum.c"
|
||||
@@ -408,43 +482,6 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "C#"
|
||||
|
||||
```csharp title="two_sum.cs"
|
||||
/* 方法二:辅助哈希表 */
|
||||
int[] twoSumHashTable(int[] nums, int target) {
|
||||
int size = nums.Length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Dictionary<int, int> dic = new();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (int i = 0; i < size; i++) {
|
||||
if (dic.ContainsKey(target - nums[i])) {
|
||||
return new int[] { dic[target - nums[i]], i };
|
||||
}
|
||||
dic.Add(nums[i], i);
|
||||
}
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
```
|
||||
|
||||
=== "Swift"
|
||||
|
||||
```swift title="two_sum.swift"
|
||||
/* 方法二:辅助哈希表 */
|
||||
func twoSumHashTable(nums: [Int], target: Int) -> [Int] {
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
var dic: [Int: Int] = [:]
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for i in nums.indices {
|
||||
if let j = dic[target - nums[i]] {
|
||||
return [j, i]
|
||||
}
|
||||
dic[nums[i]] = i
|
||||
}
|
||||
return [0]
|
||||
}
|
||||
```
|
||||
|
||||
=== "Zig"
|
||||
|
||||
```zig title="two_sum.zig"
|
||||
@@ -466,43 +503,6 @@ comments: true
|
||||
}
|
||||
```
|
||||
|
||||
=== "Dart"
|
||||
|
||||
```dart title="two_sum.dart"
|
||||
/* 方法二: 辅助哈希表 */
|
||||
List<int> twoSumHashTable(List<int> nums, int target) {
|
||||
int size = nums.length;
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
Map<int, int> dic = HashMap();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (var i = 0; i < size; i++) {
|
||||
if (dic.containsKey(target - nums[i])) {
|
||||
return [dic[target - nums[i]]!, i];
|
||||
}
|
||||
dic.putIfAbsent(nums[i], () => i);
|
||||
}
|
||||
return [0];
|
||||
}
|
||||
```
|
||||
|
||||
=== "Rust"
|
||||
|
||||
```rust title="two_sum.rs"
|
||||
/* 方法二:辅助哈希表 */
|
||||
pub fn two_sum_hash_table(nums: &Vec<i32>, target: i32) -> Option<Vec<i32>> {
|
||||
// 辅助哈希表,空间复杂度 O(n)
|
||||
let mut dic = HashMap::new();
|
||||
// 单层循环,时间复杂度 O(n)
|
||||
for (i, num) in nums.iter().enumerate() {
|
||||
match dic.get(&(target - num)) {
|
||||
Some(v) => return Some(vec![*v as i32, i as i32]),
|
||||
None => dic.insert(num, i as i32)
|
||||
};
|
||||
}
|
||||
None
|
||||
}
|
||||
```
|
||||
|
||||
此方法通过哈希查找将时间复杂度从 $O(n^2)$ 降低至 $O(n)$ ,大幅提升运行效率。
|
||||
|
||||
由于需要维护一个额外的哈希表,因此空间复杂度为 $O(n)$ 。**尽管如此,该方法的整体时空效率更为均衡,因此它是本题的最优解法**。
|
||||
|
||||
Reference in New Issue
Block a user