mirror of
https://github.com/krahets/hello-algo.git
synced 2026-02-02 18:39:30 +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