You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
hello-algo/en/docs/chapter_searching/replace_linear_by_hashing.md

258 lines
6.5 KiB

7 months ago
---
comments: true
---
# 10.4   Hash optimization strategies
In algorithm problems, **we often reduce the time complexity of algorithms by replacing linear search with hash search**. Let's use an algorithm problem to deepen understanding.
!!! question
Given an integer array `nums` and a target element `target`, please search for two elements in the array whose "sum" equals `target`, and return their array indices. Any solution is acceptable.
## 10.4.1   Linear search: trading time for space
7 months ago
Consider traversing all possible combinations directly. As shown in Figure 10-9, we initiate a two-layer loop, and in each round, we determine whether the sum of the two integers equals `target`. If so, we return their indices.
7 months ago
![Linear search solution for two-sum problem](replace_linear_by_hashing.assets/two_sum_brute_force.png){ class="animation-figure" }
<p align="center"> Figure 10-9 &nbsp; Linear search solution for two-sum problem </p>
The code is shown below:
=== "Python"
```python title="two_sum.py"
def two_sum_brute_force(nums: list[int], target: int) -> list[int]:
7 months ago
"""Method one: Brute force enumeration"""
# Two-layer loop, time complexity is O(n^2)
7 months ago
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++"
```cpp title="two_sum.cpp"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Java"
```java title="two_sum.java"
7 months ago
/* Method one: Brute force enumeration */
7 months ago
int[] twoSumBruteForce(int[] nums, int target) {
int size = nums.length;
7 months ago
// Two-layer loop, time complexity is O(n^2)
7 months ago
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"
7 months ago
[class]{two_sum}-[func]{TwoSumBruteForce}
7 months ago
```
=== "Go"
```go title="two_sum.go"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Swift"
```swift title="two_sum.swift"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "JS"
```javascript title="two_sum.js"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "TS"
```typescript title="two_sum.ts"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Dart"
```dart title="two_sum.dart"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Rust"
```rust title="two_sum.rs"
7 months ago
[class]{}-[func]{two_sum_brute_force}
7 months ago
```
=== "C"
```c title="two_sum.c"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Kotlin"
```kotlin title="two_sum.kt"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
=== "Ruby"
```ruby title="two_sum.rb"
7 months ago
[class]{}-[func]{two_sum_brute_force}
7 months ago
```
=== "Zig"
```zig title="two_sum.zig"
7 months ago
[class]{}-[func]{twoSumBruteForce}
7 months ago
```
This method has a time complexity of $O(n^2)$ and a space complexity of $O(1)$, which is very time-consuming with large data volumes.
## 10.4.2 &nbsp; Hash search: trading space for time
Consider using a hash table, with key-value pairs being the array elements and their indices, respectively. Loop through the array, performing the steps shown in the figures below each round.
1. Check if the number `target - nums[i]` is in the hash table. If so, directly return the indices of these two elements.
2. Add the key-value pair `nums[i]` and index `i` to the hash table.
=== "<1>"
![Help hash table solve two-sum](replace_linear_by_hashing.assets/two_sum_hashtable_step1.png){ class="animation-figure" }
=== "<2>"
![two_sum_hashtable_step2](replace_linear_by_hashing.assets/two_sum_hashtable_step2.png){ class="animation-figure" }
=== "<3>"
![two_sum_hashtable_step3](replace_linear_by_hashing.assets/two_sum_hashtable_step3.png){ class="animation-figure" }
<p align="center"> Figure 10-10 &nbsp; Help hash table solve two-sum </p>
The implementation code is shown below, requiring only a single loop:
=== "Python"
```python title="two_sum.py"
def two_sum_hash_table(nums: list[int], target: int) -> list[int]:
7 months ago
"""Method two: Auxiliary hash table"""
# Auxiliary hash table, space complexity is O(n)
7 months ago
dic = {}
7 months ago
# Single-layer loop, time complexity is O(n)
7 months ago
for i in range(len(nums)):
if target - nums[i] in dic:
return [dic[target - nums[i]], i]
dic[nums[i]] = i
return []
```
=== "C++"
```cpp title="two_sum.cpp"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Java"
```java title="two_sum.java"
7 months ago
/* Method two: Auxiliary hash table */
7 months ago
int[] twoSumHashTable(int[] nums, int target) {
int size = nums.length;
7 months ago
// Auxiliary hash table, space complexity is O(n)
7 months ago
Map<Integer, Integer> dic = new HashMap<>();
7 months ago
// Single-layer loop, time complexity is O(n)
7 months ago
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"
7 months ago
[class]{two_sum}-[func]{TwoSumHashTable}
7 months ago
```
=== "Go"
```go title="two_sum.go"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Swift"
```swift title="two_sum.swift"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "JS"
```javascript title="two_sum.js"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "TS"
```typescript title="two_sum.ts"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Dart"
```dart title="two_sum.dart"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Rust"
```rust title="two_sum.rs"
7 months ago
[class]{}-[func]{two_sum_hash_table}
7 months ago
```
=== "C"
```c title="two_sum.c"
7 months ago
[class]{HashTable}-[func]{}
7 months ago
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Kotlin"
```kotlin title="two_sum.kt"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
=== "Ruby"
```ruby title="two_sum.rb"
7 months ago
[class]{}-[func]{two_sum_hash_table}
7 months ago
```
=== "Zig"
```zig title="two_sum.zig"
7 months ago
[class]{}-[func]{twoSumHashTable}
7 months ago
```
This method reduces the time complexity from $O(n^2)$ to $O(n)$ by using hash search, greatly improving the running efficiency.
As it requires maintaining an additional hash table, the space complexity is $O(n)$. **Nevertheless, this method has a more balanced time-space efficiency overall, making it the optimal solution for this problem**.