Bug fixes and improvements (#1732)

* Bug fixes

* Sync zh and zh-hant versions.

* "入列列" -> "入佇列"

* Fix hello_algo_mindmap.png
This commit is contained in:
Yudong Jin
2025-04-10 19:21:52 +08:00
committed by GitHub
parent a9d44c3a25
commit 8e38c61455
14 changed files with 48 additions and 49 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 150 KiB

View File

@ -6,4 +6,4 @@
Complexity analysis is like a space-time navigator in the vast universe of algorithms.
It guides us in exploring deeper within the the dimensions of time and space, seeking more elegant solutions.
It guides us in exploring deeper within the dimensions of time and space, seeking more elegant solutions.

View File

@ -31,7 +31,7 @@ function xorHash(key) {
for (const c of key) {
hash ^= c.charCodeAt(0);
}
return hash & MODULUS;
return hash % MODULUS;
}
/* 旋轉雜湊 */

View File

@ -9,9 +9,7 @@ def counting_sort_naive(nums: list[int]):
"""計數排序"""
# 簡單實現,無法用於排序物件
# 1. 統計陣列最大元素 m
m = 0
for num in nums:
m = max(m, num)
m = max(nums)
# 2. 統計各數字的出現次數
# counter[num] 代表 num 的出現次數
counter = [0] * (m + 1)

View File

@ -19,8 +19,7 @@ struct MyList {
impl MyList {
/* 建構子 */
pub fn new(capacity: usize) -> Self {
let mut vec = Vec::new();
vec.resize(capacity, 0);
let mut vec = vec![0; capacity];
Self {
arr: vec,
capacity,
@ -92,7 +91,7 @@ impl MyList {
};
let num = self.arr[index];
// 將將索引 index 之後的元素都向前移動一位
for j in (index..self.size - 1) {
for j in index..self.size - 1 {
self.arr[j] = self.arr[j + 1];
}
// 更新元素數量
@ -111,7 +110,7 @@ impl MyList {
}
/* 將串列轉換為陣列 */
pub fn to_array(&mut self) -> Vec<i32> {
pub fn to_array(&self) -> Vec<i32> {
// 僅轉換有效長度範圍內的串列元素
let mut arr = Vec::new();
for i in 0..self.size {

View File

@ -13,10 +13,10 @@ struct Pair {
/* 鏈式位址雜湊表 */
struct HashMapChaining {
size: i32,
capacity: i32,
size: usize,
capacity: usize,
load_thres: f32,
extend_ratio: i32,
extend_ratio: usize,
buckets: Vec<Vec<Pair>>,
}
@ -34,7 +34,7 @@ impl HashMapChaining {
/* 雜湊函式 */
fn hash_func(&self, key: i32) -> usize {
key as usize % self.capacity as usize
key as usize % self.capacity
}
/* 負載因子 */
@ -45,12 +45,11 @@ impl HashMapChaining {
/* 刪除操作 */
fn remove(&mut self, key: i32) -> Option<String> {
let index = self.hash_func(key);
let bucket = &mut self.buckets[index];
// 走訪桶,從中刪除鍵值對
for i in 0..bucket.len() {
if bucket[i].key == key {
let pair = bucket.remove(i);
for (i, p) in self.buckets[index].iter_mut().enumerate() {
if p.key == key {
let pair = self.buckets[index].remove(i);
self.size -= 1;
return Some(pair.val);
}
@ -63,7 +62,7 @@ impl HashMapChaining {
/* 擴容雜湊表 */
fn extend(&mut self) {
// 暫存原雜湊表
let buckets_tmp = std::mem::replace(&mut self.buckets, vec![]);
let buckets_tmp = std::mem::take(&mut self.buckets);
// 初始化擴容後的新雜湊表
self.capacity *= self.extend_ratio;
@ -97,30 +96,27 @@ impl HashMapChaining {
}
let index = self.hash_func(key);
let bucket = &mut self.buckets[index];
// 走訪桶,若遇到指定 key ,則更新對應 val 並返回
for pair in bucket {
for pair in self.buckets[index].iter_mut() {
if pair.key == key {
pair.val = val;
return;
}
}
let bucket = &mut self.buckets[index];
// 若無該 key ,則將鍵值對新增至尾部
let pair = Pair { key, val };
bucket.push(pair);
self.buckets[index].push(pair);
self.size += 1;
}
/* 查詢操作 */
fn get(&self, key: i32) -> Option<&str> {
let index = self.hash_func(key);
let bucket = &self.buckets[index];
// 走訪桶,若找到 key ,則返回對應 val
for pair in bucket {
for pair in self.buckets[index].iter() {
if pair.key == key {
return Some(&pair.val);
}

View File

@ -120,7 +120,7 @@ impl<T: Copy> LinkedListDeque<T> {
}
}
self.que_size -= 1; // 更新佇列長度
Rc::try_unwrap(old_front).ok().unwrap().into_inner().val
old_front.borrow().val
})
}
// 佇列尾出列操作
@ -136,7 +136,7 @@ impl<T: Copy> LinkedListDeque<T> {
}
}
self.que_size -= 1; // 更新佇列長度
Rc::try_unwrap(old_rear).ok().unwrap().into_inner().val
old_rear.borrow().val
})
}
}
@ -163,12 +163,16 @@ impl<T: Copy> LinkedListDeque<T> {
/* 返回陣列用於列印 */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = self.to_array(node.borrow().next.as_ref());
nums.insert(0, node.borrow().val);
return nums;
let mut res: Vec<T> = Vec::new();
fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) {
if let Some(cur) = cur {
res.push(cur.borrow().val);
recur(cur.borrow().next.as_ref(), res);
}
}
return Vec::new();
recur(head, &mut res);
res
}
}

View File

@ -67,7 +67,7 @@ impl<T: Copy> LinkedListQueue<T> {
}
}
self.que_size -= 1;
Rc::try_unwrap(old_front).ok().unwrap().into_inner().val
old_front.borrow().val
})
}
@ -78,12 +78,18 @@ impl<T: Copy> LinkedListQueue<T> {
/* 將鏈結串列轉化為 Array 並返回 */
pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> {
if let Some(node) = head {
let mut nums = self.to_array(node.borrow().next.as_ref());
nums.insert(0, node.borrow().val);
return nums;
let mut res: Vec<T> = Vec::new();
fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) {
if let Some(cur) = cur {
res.push(cur.borrow().val);
recur(cur.borrow().next.as_ref(), res);
}
}
return Vec::new();
recur(head, &mut res);
res
}
}

View File

@ -45,16 +45,10 @@ impl<T: Copy> LinkedListStack<T> {
/* 出堆疊 */
pub fn pop(&mut self) -> Option<T> {
self.stack_peek.take().map(|old_head| {
match old_head.borrow_mut().next.take() {
Some(new_head) => {
self.stack_peek = Some(new_head);
}
None => {
self.stack_peek = None;
}
}
self.stack_peek = old_head.borrow_mut().next.take();
self.stk_size -= 1;
Rc::try_unwrap(old_head).ok().unwrap().into_inner().val
old_head.borrow().val
})
}

View File

@ -31,7 +31,7 @@ function xorHash(key: string): number {
for (const c of key) {
hash ^= c.charCodeAt(0);
}
return hash & MODULUS;
return hash % MODULUS;
}
/* 旋轉雜湊 */

View File

@ -11,7 +11,7 @@
- 子集和問題的目標是在給定集合中找到和為目標值的所有子集。集合不區分元素順序,而搜尋過程會輸出所有順序的結果,產生重複子集。我們在回溯前將資料進行排序,並設定一個變數來指示每一輪的走訪起始點,從而將生成重複子集的搜尋分支進行剪枝。
- 對於子集和問題,陣列中的相等元素會產生重複集合。我們利用陣列已排序的前置條件,透過判斷相鄰元素是否相等實現剪枝,從而確保相等元素在每輪中只能被選中一次。
- $n$ 皇后問題旨在尋找將 $n$ 個皇后放置到 $n \times n$ 尺寸棋盤上的方案,要求所有皇后兩兩之間無法攻擊對方。該問題的約束條件有行約束、列約束、主對角線和次對角線約束。為滿足行約束,我們採用按行放置的策略,保證每一行放置一個皇后。
- 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找處在同一主(副)對角線上格子滿足的行列索引規律。
- 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找處在同一主(副)對角線上格子滿足的行列索引規律。
### Q & A

View File

@ -33,6 +33,8 @@
[file]{fractional_knapsack}-[class]{}-[func]{fractional_knapsack}
```
內建排序演算法的時間複雜度通常為 $O(\log n)$ ,空間複雜度通常為 $O(\log n)$ 或 $O(n)$ ,取決於程式語言的具體實現。
除排序之外,在最差情況下,需要走訪整個物品串列,**因此時間複雜度為 $O(n)$** ,其中 $n$ 為物品數量。
由於初始化了一個 `Item` 物件串列,**因此空間複雜度為 $O(n)$** 。

Binary file not shown.

Before

Width:  |  Height:  |  Size: 161 KiB

After

Width:  |  Height:  |  Size: 160 KiB

View File

@ -425,5 +425,5 @@
## 佇列典型應用
- **淘寶訂單**。購物者下單後,訂單將加入列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。
- **淘寶訂單**。購物者下單後,訂單將加入列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。
- **各類待辦事項**。任何需要實現“先來後到”功能的場景,例如印表機的任務佇列、餐廳的出餐佇列等,佇列在這些場景中可以有效地維護處理順序。