mirror of
				https://github.com/krahets/hello-algo.git
				synced 2025-10-31 10:26: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. | ||||
|  | ||||
|     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) { | ||||
|         hash ^= c.charCodeAt(0); | ||||
|     } | ||||
|     return hash & MODULUS; | ||||
|     return hash % MODULUS; | ||||
| } | ||||
|  | ||||
| /* 旋轉雜湊 */ | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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 { | ||||
|  | ||||
| @ -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); | ||||
|             } | ||||
|  | ||||
| @ -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 | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -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 | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @ -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 | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|  | ||||
| @ -31,7 +31,7 @@ function xorHash(key: string): number { | ||||
|     for (const c of key) { | ||||
|         hash ^= c.charCodeAt(0); | ||||
|     } | ||||
|     return hash & MODULUS; | ||||
|     return hash % MODULUS; | ||||
| } | ||||
|  | ||||
| /* 旋轉雜湊 */ | ||||
|  | ||||
| @ -11,7 +11,7 @@ | ||||
| - 子集和問題的目標是在給定集合中找到和為目標值的所有子集。集合不區分元素順序,而搜尋過程會輸出所有順序的結果,產生重複子集。我們在回溯前將資料進行排序,並設定一個變數來指示每一輪的走訪起始點,從而將生成重複子集的搜尋分支進行剪枝。 | ||||
| - 對於子集和問題,陣列中的相等元素會產生重複集合。我們利用陣列已排序的前置條件,透過判斷相鄰元素是否相等實現剪枝,從而確保相等元素在每輪中只能被選中一次。 | ||||
| - $n$ 皇后問題旨在尋找將 $n$ 個皇后放置到 $n \times n$ 尺寸棋盤上的方案,要求所有皇后兩兩之間無法攻擊對方。該問題的約束條件有行約束、列約束、主對角線和次對角線約束。為滿足行約束,我們採用按行放置的策略,保證每一行放置一個皇后。 | ||||
| - 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找處在到同一主(副)對角線上格子滿足的行列索引規律。 | ||||
| - 列約束和對角線約束的處理方式類似。對於列約束,我們利用一個陣列來記錄每一列是否有皇后,從而指示選中的格子是否合法。對於對角線約束,我們藉助兩個陣列來分別記錄該主、次對角線上是否存在皇后;難點在於找出處在同一主(副)對角線上的格子所滿足的行列索引規律。 | ||||
|  | ||||
| ### Q & A | ||||
|  | ||||
|  | ||||
| @ -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 | 
| @ -425,5 +425,5 @@ | ||||
|  | ||||
| ## 佇列典型應用 | ||||
|  | ||||
| - **淘寶訂單**。購物者下單後,訂單將加入列列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。 | ||||
| - **淘寶訂單**。購物者下單後,訂單將加入佇列中,系統隨後會根據順序處理佇列中的訂單。在雙十一期間,短時間內會產生海量訂單,高併發成為工程師們需要重點攻克的問題。 | ||||
| - **各類待辦事項**。任何需要實現“先來後到”功能的場景,例如印表機的任務佇列、餐廳的出餐佇列等,佇列在這些場景中可以有效地維護處理順序。 | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 Yudong Jin
					Yudong Jin