mirror of
				https://github.com/krahets/hello-algo.git
				synced 2025-10-31 18:37:48 +08:00 
			
		
		
		
	Bug fixes and improvements (#1732)
* Bug fixes * Sync zh and zh-hant versions. * "入列列" -> "入佇列" * Fix hello_algo_mindmap.png
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 150 KiB After Width: | Height: | Size: 150 KiB | 
| @ -6,4 +6,4 @@ | |||||||
|  |  | ||||||
|     Complexity analysis is like a space-time navigator in the vast universe of algorithms. |     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. | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ function xorHash(key) { | |||||||
|     for (const c of key) { |     for (const c of key) { | ||||||
|         hash ^= c.charCodeAt(0); |         hash ^= c.charCodeAt(0); | ||||||
|     } |     } | ||||||
|     return hash & MODULUS; |     return hash % MODULUS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* 旋轉雜湊 */ | /* 旋轉雜湊 */ | ||||||
|  | |||||||
| @ -9,9 +9,7 @@ def counting_sort_naive(nums: list[int]): | |||||||
|     """計數排序""" |     """計數排序""" | ||||||
|     # 簡單實現,無法用於排序物件 |     # 簡單實現,無法用於排序物件 | ||||||
|     # 1. 統計陣列最大元素 m |     # 1. 統計陣列最大元素 m | ||||||
|     m = 0 |     m = max(nums) | ||||||
|     for num in nums: |  | ||||||
|         m = max(m, num) |  | ||||||
|     # 2. 統計各數字的出現次數 |     # 2. 統計各數字的出現次數 | ||||||
|     # counter[num] 代表 num 的出現次數 |     # counter[num] 代表 num 的出現次數 | ||||||
|     counter = [0] * (m + 1) |     counter = [0] * (m + 1) | ||||||
|  | |||||||
| @ -19,8 +19,7 @@ struct MyList { | |||||||
| impl MyList { | impl MyList { | ||||||
|     /* 建構子 */ |     /* 建構子 */ | ||||||
|     pub fn new(capacity: usize) -> Self { |     pub fn new(capacity: usize) -> Self { | ||||||
|         let mut vec = Vec::new(); |         let mut vec = vec![0; capacity]; | ||||||
|         vec.resize(capacity, 0); |  | ||||||
|         Self { |         Self { | ||||||
|             arr: vec, |             arr: vec, | ||||||
|             capacity, |             capacity, | ||||||
| @ -92,7 +91,7 @@ impl MyList { | |||||||
|         }; |         }; | ||||||
|         let num = self.arr[index]; |         let num = self.arr[index]; | ||||||
|         // 將將索引 index 之後的元素都向前移動一位 |         // 將將索引 index 之後的元素都向前移動一位 | ||||||
|         for j in (index..self.size - 1) { |         for j in index..self.size - 1 { | ||||||
|             self.arr[j] = self.arr[j + 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(); |         let mut arr = Vec::new(); | ||||||
|         for i in 0..self.size { |         for i in 0..self.size { | ||||||
|  | |||||||
| @ -13,10 +13,10 @@ struct Pair { | |||||||
|  |  | ||||||
| /* 鏈式位址雜湊表 */ | /* 鏈式位址雜湊表 */ | ||||||
| struct HashMapChaining { | struct HashMapChaining { | ||||||
|     size: i32, |     size: usize, | ||||||
|     capacity: i32, |     capacity: usize, | ||||||
|     load_thres: f32, |     load_thres: f32, | ||||||
|     extend_ratio: i32, |     extend_ratio: usize, | ||||||
|     buckets: Vec<Vec<Pair>>, |     buckets: Vec<Vec<Pair>>, | ||||||
| } | } | ||||||
|  |  | ||||||
| @ -34,7 +34,7 @@ impl HashMapChaining { | |||||||
|  |  | ||||||
|     /* 雜湊函式 */ |     /* 雜湊函式 */ | ||||||
|     fn hash_func(&self, key: i32) -> usize { |     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> { |     fn remove(&mut self, key: i32) -> Option<String> { | ||||||
|         let index = self.hash_func(key); |         let index = self.hash_func(key); | ||||||
|         let bucket = &mut self.buckets[index]; |  | ||||||
|  |  | ||||||
|         // 走訪桶,從中刪除鍵值對 |         // 走訪桶,從中刪除鍵值對 | ||||||
|         for i in 0..bucket.len() { |         for (i, p) in self.buckets[index].iter_mut().enumerate() { | ||||||
|             if bucket[i].key == key { |             if p.key == key { | ||||||
|                 let pair = bucket.remove(i); |                 let pair = self.buckets[index].remove(i); | ||||||
|                 self.size -= 1; |                 self.size -= 1; | ||||||
|                 return Some(pair.val); |                 return Some(pair.val); | ||||||
|             } |             } | ||||||
| @ -63,7 +62,7 @@ impl HashMapChaining { | |||||||
|     /* 擴容雜湊表 */ |     /* 擴容雜湊表 */ | ||||||
|     fn extend(&mut self) { |     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; |         self.capacity *= self.extend_ratio; | ||||||
| @ -97,30 +96,27 @@ impl HashMapChaining { | |||||||
|         } |         } | ||||||
|  |  | ||||||
|         let index = self.hash_func(key); |         let index = self.hash_func(key); | ||||||
|         let bucket = &mut self.buckets[index]; |  | ||||||
|  |  | ||||||
|         // 走訪桶,若遇到指定 key ,則更新對應 val 並返回 |         // 走訪桶,若遇到指定 key ,則更新對應 val 並返回 | ||||||
|         for pair in bucket { |         for pair in self.buckets[index].iter_mut() { | ||||||
|             if pair.key == key { |             if pair.key == key { | ||||||
|                 pair.val = val; |                 pair.val = val; | ||||||
|                 return; |                 return; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|         let bucket = &mut self.buckets[index]; |  | ||||||
|  |  | ||||||
|         // 若無該 key ,則將鍵值對新增至尾部 |         // 若無該 key ,則將鍵值對新增至尾部 | ||||||
|         let pair = Pair { key, val }; |         let pair = Pair { key, val }; | ||||||
|         bucket.push(pair); |         self.buckets[index].push(pair); | ||||||
|         self.size += 1; |         self.size += 1; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     /* 查詢操作 */ |     /* 查詢操作 */ | ||||||
|     fn get(&self, key: i32) -> Option<&str> { |     fn get(&self, key: i32) -> Option<&str> { | ||||||
|         let index = self.hash_func(key); |         let index = self.hash_func(key); | ||||||
|         let bucket = &self.buckets[index]; |  | ||||||
|  |  | ||||||
|         // 走訪桶,若找到 key ,則返回對應 val |         // 走訪桶,若找到 key ,則返回對應 val | ||||||
|         for pair in bucket { |         for pair in self.buckets[index].iter() { | ||||||
|             if pair.key == key { |             if pair.key == key { | ||||||
|                 return Some(&pair.val); |                 return Some(&pair.val); | ||||||
|             } |             } | ||||||
|  | |||||||
| @ -120,7 +120,7 @@ impl<T: Copy> LinkedListDeque<T> { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|                 self.que_size -= 1; // 更新佇列長度 |                 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; // 更新佇列長度 |                 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> { |     pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> { | ||||||
|         if let Some(node) = head { |         let mut res: Vec<T> = Vec::new(); | ||||||
|             let mut nums = self.to_array(node.borrow().next.as_ref()); |         fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) { | ||||||
|             nums.insert(0, node.borrow().val); |             if let Some(cur) = cur { | ||||||
|             return nums; |                 res.push(cur.borrow().val); | ||||||
|  |                 recur(cur.borrow().next.as_ref(), res); | ||||||
|             } |             } | ||||||
|         return Vec::new(); |         } | ||||||
|  |  | ||||||
|  |         recur(head, &mut res); | ||||||
|  |         res | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -67,7 +67,7 @@ impl<T: Copy> LinkedListQueue<T> { | |||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             self.que_size -= 1; |             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 並返回 */ |     /* 將鏈結串列轉化為 Array 並返回 */ | ||||||
|     pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> { |     pub fn to_array(&self, head: Option<&Rc<RefCell<ListNode<T>>>>) -> Vec<T> { | ||||||
|         if let Some(node) = head { |         let mut res: Vec<T> = Vec::new(); | ||||||
|             let mut nums = self.to_array(node.borrow().next.as_ref()); |  | ||||||
|             nums.insert(0, node.borrow().val); |         fn recur<T: Copy>(cur: Option<&Rc<RefCell<ListNode<T>>>>, res: &mut Vec<T>) { | ||||||
|             return nums; |             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 | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -45,16 +45,10 @@ impl<T: Copy> LinkedListStack<T> { | |||||||
|     /* 出堆疊 */ |     /* 出堆疊 */ | ||||||
|     pub fn pop(&mut self) -> Option<T> { |     pub fn pop(&mut self) -> Option<T> { | ||||||
|         self.stack_peek.take().map(|old_head| { |         self.stack_peek.take().map(|old_head| { | ||||||
|             match old_head.borrow_mut().next.take() { |             self.stack_peek = old_head.borrow_mut().next.take(); | ||||||
|                 Some(new_head) => { |  | ||||||
|                     self.stack_peek = Some(new_head); |  | ||||||
|                 } |  | ||||||
|                 None => { |  | ||||||
|                     self.stack_peek = None; |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             self.stk_size -= 1; |             self.stk_size -= 1; | ||||||
|             Rc::try_unwrap(old_head).ok().unwrap().into_inner().val |  | ||||||
|  |             old_head.borrow().val | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | |||||||
| @ -31,7 +31,7 @@ function xorHash(key: string): number { | |||||||
|     for (const c of key) { |     for (const c of key) { | ||||||
|         hash ^= c.charCodeAt(0); |         hash ^= c.charCodeAt(0); | ||||||
|     } |     } | ||||||
|     return hash & MODULUS; |     return hash % MODULUS; | ||||||
| } | } | ||||||
|  |  | ||||||
| /* 旋轉雜湊 */ | /* 旋轉雜湊 */ | ||||||
|  | |||||||
| @ -11,7 +11,7 @@ | |||||||
| - 子集和問題的目標是在給定集合中找到和為目標值的所有子集。集合不區分元素順序,而搜尋過程會輸出所有順序的結果,產生重複子集。我們在回溯前將資料進行排序,並設定一個變數來指示每一輪的走訪起始點,從而將生成重複子集的搜尋分支進行剪枝。 | - 子集和問題的目標是在給定集合中找到和為目標值的所有子集。集合不區分元素順序,而搜尋過程會輸出所有順序的結果,產生重複子集。我們在回溯前將資料進行排序,並設定一個變數來指示每一輪的走訪起始點,從而將生成重複子集的搜尋分支進行剪枝。 | ||||||
| - 對於子集和問題,陣列中的相等元素會產生重複集合。我們利用陣列已排序的前置條件,透過判斷相鄰元素是否相等實現剪枝,從而確保相等元素在每輪中只能被選中一次。 | - 對於子集和問題,陣列中的相等元素會產生重複集合。我們利用陣列已排序的前置條件,透過判斷相鄰元素是否相等實現剪枝,從而確保相等元素在每輪中只能被選中一次。 | ||||||
| - $n$ 皇后問題旨在尋找將 $n$ 個皇后放置到 $n \times n$ 尺寸棋盤上的方案,要求所有皇后兩兩之間無法攻擊對方。該問題的約束條件有行約束、列約束、主對角線和次對角線約束。為滿足行約束,我們採用按行放置的策略,保證每一行放置一個皇后。 | - $n$ 皇后問題旨在尋找將 $n$ 個皇后放置到 $n \times n$ 尺寸棋盤上的方案,要求所有皇后兩兩之間無法攻擊對方。該問題的約束條件有行約束、列約束、主對角線和次對角線約束。為滿足行約束,我們採用按行放置的策略,保證每一行放置一個皇后。 | ||||||
| - 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找處在到同一主(副)對角線上格子滿足的行列索引規律。 | - 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找出處在同一主(副)對角線上的格子所滿足的行列索引規律。 | ||||||
|  |  | ||||||
| ### Q & A | ### Q & A | ||||||
|  |  | ||||||
|  | |||||||
| @ -33,6 +33,8 @@ | |||||||
| [file]{fractional_knapsack}-[class]{}-[func]{fractional_knapsack} | [file]{fractional_knapsack}-[class]{}-[func]{fractional_knapsack} | ||||||
| ``` | ``` | ||||||
|  |  | ||||||
|  | 內建排序演算法的時間複雜度通常為 $O(\log n)$ ,空間複雜度通常為 $O(\log n)$ 或 $O(n)$ ,取決於程式語言的具體實現。 | ||||||
|  |  | ||||||
| 除排序之外,在最差情況下,需要走訪整個物品串列,**因此時間複雜度為 $O(n)$** ,其中 $n$ 為物品數量。 | 除排序之外,在最差情況下,需要走訪整個物品串列,**因此時間複雜度為 $O(n)$** ,其中 $n$ 為物品數量。 | ||||||
|  |  | ||||||
| 由於初始化了一個 `Item` 物件串列,**因此空間複雜度為 $O(n)$** 。 | 由於初始化了一個 `Item` 物件串列,**因此空間複雜度為 $O(n)$** 。 | ||||||
|  | |||||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 161 KiB After Width: | Height: | Size: 160 KiB | 
| @ -425,5 +425,5 @@ | |||||||
|  |  | ||||||
| ## 佇列典型應用 | ## 佇列典型應用 | ||||||
|  |  | ||||||
| - **淘寶訂單**。購物者下單後,訂單將加入列列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。 | - **淘寶訂單**。購物者下單後,訂單將加入佇列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。 | ||||||
| - **各類待辦事項**。任何需要實現“先來後到”功能的場景,例如印表機的任務佇列、餐廳的出餐佇列等,佇列在這些場景中可以有效地維護處理順序。 | - **各類待辦事項**。任何需要實現“先來後到”功能的場景,例如印表機的任務佇列、餐廳的出餐佇列等,佇列在這些場景中可以有效地維護處理順序。 | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user
	 Yudong Jin
					Yudong Jin