From 5b029ad63226dcc9a25915ac73c7b0ffee66aed0 Mon Sep 17 00:00:00 2001
From: krahets 可视化运行
-
+
+全屏观看 >
数组元素被存储在连续的内存空间中,这意味着计算数组元素的内存地址非常容易。给定数组内存地址(首元素内存地址)和某个元素的索引,我们可以使用图 4-2 所示的公式计算得到该元素的内存地址,从而直接访问该元素。
@@ -3910,8 +3911,8 @@数组元素在内存中是“紧挨着的”,它们之间没有空间再存放任何数据。如图 4-3 所示,如果想在数组中间插入一个元素,则需要将该元素之后的所有元素都向后移动一位,之后再把元素赋值给该索引。
@@ -4068,8 +4069,8 @@同理,如图 4-4 所示,若想删除索引 \(i\) 处的元素,则需要把索引 \(i\) 之后的元素都向前移动一位。
@@ -4203,8 +4204,8 @@总的来看,数组的插入与删除操作有以下缺点。
在数组中查找指定元素需要遍历数组,每轮判断元素值是否匹配,若匹配则输出对应索引。
@@ -4550,8 +4551,8 @@在复杂的系统环境中,程序难以保证数组之后的内存空间是可用的,从而无法安全地扩展数组容量。因此在大多数编程语言中,数组的长度是不可变的。
@@ -4737,8 +4738,8 @@数组存储在连续的内存空间内,且元素类型相同。这种做法包含丰富的先验信息,系统可以利用这些信息来优化数据结构的操作效率。
diff --git a/chapter_array_and_linkedlist/linked_list/index.html b/chapter_array_and_linkedlist/linked_list/index.html index bc89819a3..0adb936f1 100644 --- a/chapter_array_and_linkedlist/linked_list/index.html +++ b/chapter_array_and_linkedlist/linked_list/index.html @@ -3999,7 +3999,8 @@数组整体是一个变量,比如数组 nums
包含元素 nums[0]
和 nums[1]
等,而链表是由多个独立的节点对象组成的。我们通常将头节点当作链表的代称,比如以上代码中的链表可记作链表 n0
。
如图 4-7 所示,在链表中删除节点也非常方便,只需改变一个节点的引用(指针)即可。
@@ -4288,8 +4289,8 @@在链表中访问节点的效率较低。如上一节所述,我们可以在 \(O(1)\) 时间下访问数组中的任意元素。链表则不然,程序需要从头节点出发,逐个向后遍历,直至找到目标节点。也就是说,访问链表的第 \(i\) 个节点需要循环 \(i - 1\) 轮,时间复杂度为 \(O(n)\) 。
@@ -4445,8 +4446,8 @@遍历链表,查找其中值为 target
的节点,输出该节点在链表中的索引。此过程也属于线性查找。代码如下所示:
表 4-1 总结了数组和链表的各项特点并对比了操作效率。由于它们采用两种相反的存储策略,因此各种性质和操作效率也呈现对立的特点。
diff --git a/chapter_array_and_linkedlist/list/index.html b/chapter_array_and_linkedlist/list/index.html index 708dbf171..956825c93 100644 --- a/chapter_array_and_linkedlist/list/index.html +++ b/chapter_array_and_linkedlist/list/index.html @@ -3746,7 +3746,8 @@列表本质上是数组,因此可以在 \(O(1)\) 时间内访问和更新元素,效率很高。
@@ -3847,7 +3848,8 @@相较于数组,列表可以自由地添加与删除元素。在列表尾部添加元素的时间复杂度为 \(O(1)\) ,但插入和删除元素的效率仍与数组相同,时间复杂度为 \(O(n)\) 。
@@ -4059,7 +4061,8 @@与数组一样,列表可以根据索引遍历,也可以直接遍历各元素。
@@ -4224,7 +4227,8 @@给定一个新列表 nums1
,我们可以将其拼接到原列表的尾部。
完成列表排序后,我们便可以使用在数组类算法题中经常考查的“二分查找”和“双指针”算法。
@@ -4376,7 +4381,8 @@许多编程语言内置了列表,例如 Java、C++、Python 等。它们的实现比较复杂,各个参数的设定也非常考究,例如初始容量、扩容倍数等。感兴趣的读者可以查阅源码进行学习。
@@ -5618,8 +5624,8 @@图 13-1 在前序遍历中搜索节点
@@ -4013,8 +4013,8 @@在每次“尝试”中,我们通过将当前节点添加进 path
来记录路径;而在“回退”前,我们需要将该节点从 path
中弹出,以恢复本次尝试之前的状态。
观察图 13-2 所示的过程,我们可以将尝试和回退理解为“前进”与“撤销”,两个操作互为逆向。
@@ -4304,8 +4304,8 @@“剪枝”是一个非常形象的名词。如图 13-3 所示,在搜索过程中,我们“剪掉”了不满足约束条件的搜索分支,避免许多无意义的尝试,从而提高了搜索效率。
@@ -5139,8 +5139,8 @@根据题意,我们在找到值为 \(7\) 的节点后应该继续搜索,因此需要将记录解之后的 return
语句删除。图 13-4 对比了保留或删除 return
语句的搜索过程。
逐行放置 \(n\) 次,考虑列约束,则从第一行到最后一行分别有 \(n\)、\(n-1\)、\(\dots\)、\(2\)、\(1\) 个选择,因此时间复杂度为 \(O(n!)\) 。实际上,根据对角线约束的剪枝也能够大幅缩小搜索空间,因而搜索效率往往优于以上时间复杂度。
数组 state
使用 \(O(n^2)\) 空间,数组 cols
、diags1
和 diags2
皆使用 \(O(n)\) 空间。最大递归深度为 \(n\) ,使用 \(O(n)\) 栈帧空间。因此,空间复杂度为 \(O(n^2)\) 。
假设元素两两之间互不相同,则 \(n\) 个元素共有 \(n!\) 种排列(阶乘);在记录结果时,需要复制长度为 \(n\) 的列表,使用 \(O(n)\) 时间。因此时间复杂度为 \(O(n!n)\) 。
最大递归深度为 \(n\) ,使用 \(O(n)\) 栈帧空间。selected
使用 \(O(n)\) 空间。同一时刻最多共有 \(n\) 个 duplicated
,使用 \(O(n^2)\) 空间。因此空间复杂度为 \(O(n^2)\) 。
向以上代码输入数组 \([3, 4, 5]\) 和目标元素 \(9\) ,输出结果为 \([3, 3, 3], [4, 5], [5, 4]\) 。虽然成功找出了所有和为 \(9\) 的子集,但其中存在重复的子集 \([4, 5]\) 和 \([5, 4]\) 。
这是因为搜索过程是区分选择顺序的,然而子集不区分选择顺序。如图 13-10 所示,先选 \(4\) 后选 \(5\) 与先选 \(5\) 后选 \(4\) 是不同的分支,但对应同一个子集。
@@ -4486,8 +4486,8 @@图 13-12 所示为将数组 \([3, 4, 5]\) 和目标元素 \(9\) 输入以上代码后的整体回溯过程。
@@ -4980,8 +4980,8 @@图 13-14 展示了数组 \([4, 4, 5]\) 和目标元素 \(9\) 的回溯过程,共包含四种剪枝操作。请你将图示与代码注释相结合,理解整个搜索过程,以及每种剪枝操作是如何工作的。
diff --git a/chapter_computational_complexity/iteration_and_recursion/index.html b/chapter_computational_complexity/iteration_and_recursion/index.html index fb8a3db00..80a08bdfa 100644 --- a/chapter_computational_complexity/iteration_and_recursion/index.html +++ b/chapter_computational_complexity/iteration_and_recursion/index.html @@ -3819,8 +3819,8 @@图 2-1 是该求和函数的流程框图。
@@ -4004,8 +4004,8 @@while
循环比 for
循环的自由度更高。在 while
循环中,我们可以自由地设计条件变量的初始化和更新步骤。
例如在以下代码中,条件变量 \(i\) 每轮进行两次更新,这种情况就不太方便用 for
循环实现:
总的来说,for
循环的代码更加紧凑,while
循环更加灵活,两者都可以实现迭代结构。选择使用哪一个应该根据特定问题的需求来决定。
图 2-2 是该嵌套循环的流程框图。
@@ -4586,8 +4586,8 @@图 2-3 展示了该函数的递归过程。
@@ -4759,8 +4759,8 @@尾递归的执行过程如图 2-5 所示。对比普通递归和尾递归,两者的求和操作的执行点是不同的。
观察以上代码,我们在函数内递归调用了两个函数,这意味着从一个调用产生了两个调用分支。如图 2-6 所示,这样不断递归调用下去,最终将产生一棵层数为 \(n\) 的「递归树 recursion tree」。
@@ -5267,8 +5267,8 @@观察以上代码,当递归转化为迭代后,代码变得更加复杂了。尽管迭代和递归在很多情况下可以互相转化,但不一定值得这样做,有以下两点原因。
线性阶常见于元素数量与 \(n\) 成正比的数组、链表、栈、队列等:
@@ -4862,8 +4862,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline如图 2-17 所示,此函数的递归深度为 \(n\) ,即同时存在 \(n\) 个未返回的 linear_recur()
函数,使用 \(O(n)\) 大小的栈帧空间:
图 2-17 递归函数产生的线性阶空间复杂度
@@ -5189,8 +5189,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline如图 2-18 所示,该函数的递归深度为 \(n\) ,在每个递归函数中都初始化了一个数组,长度分别为 \(n\)、\(n-1\)、\(\dots\)、\(2\)、\(1\) ,平均长度为 \(n / 2\) ,因此总体占用 \(O(n^2)\) 空间:
图 2-18 递归函数产生的平方阶空间复杂度
@@ -5487,8 +5487,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newline图 2-19 满二叉树产生的指数阶空间复杂度
diff --git a/chapter_computational_complexity/time_complexity/index.html b/chapter_computational_complexity/time_complexity/index.html index 4ccfccf43..173a86d96 100644 --- a/chapter_computational_complexity/time_complexity/index.html +++ b/chapter_computational_complexity/time_complexity/index.html @@ -4761,8 +4761,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!线性阶的操作数量相对于输入数据大小 \(n\) 以线性级别增长。线性阶通常出现在单层循环中:
@@ -4896,8 +4896,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!遍历数组和遍历链表等操作的时间复杂度均为 \(O(n)\) ,其中 \(n\) 为数组或链表的长度:
值得注意的是,输入数据大小 \(n\) 需根据输入数据的类型来具体确定。比如在第一个示例中,变量 \(n\) 为输入数据大小;在第二个示例中,数组长度 \(n\) 为数据大小。
图 2-10 对比了常数阶、线性阶和平方阶三种时间复杂度。
@@ -5489,8 +5489,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!生物学的“细胞分裂”是指数阶增长的典型例子:初始状态为 \(1\) 个细胞,分裂一轮后变为 \(2\) 个,分裂两轮后变为 \(4\) 个,以此类推,分裂 \(n\) 轮后有 \(2^n\) 个细胞。
@@ -5699,8 +5699,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!图 2-11 指数阶的时间复杂度
@@ -5817,8 +5817,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!指数阶增长非常迅速,在穷举法(暴力搜索、回溯等)中比较常见。对于数据规模较大的问题,指数阶是不可接受的,通常需要使用动态规划或贪心算法等来解决。
图 2-12 对数阶的时间复杂度
@@ -6093,8 +6093,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!对数阶常出现于基于分治策略的算法中,体现了“一分为多”和“化繁为简”的算法思想。它增长缓慢,是仅次于常数阶的理想的时间复杂度。
图 2-13 展示了线性对数阶的生成方式。二叉树的每一层的操作总数都为 \(n\) ,树共有 \(\log_2 n + 1\) 层,因此时间复杂度为 \(O(n \log n)\) 。
@@ -6450,8 +6450,8 @@ n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1图 2-14 阶乘阶的时间复杂度
@@ -6793,8 +6793,8 @@ n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1值得说明的是,我们在实际中很少使用最佳时间复杂度,因为通常只有在很小概率下才能达到,可能会带来一定的误导性。而最差时间复杂度更为实用,因为它给出了一个效率安全值,让我们可以放心地使用算法。
从上述示例可以看出,最差时间复杂度和最佳时间复杂度只出现于“特殊的数据分布”,这些情况的出现概率可能很小,并不能真实地反映算法运行效率。相比之下,平均时间复杂度可以体现算法在随机输入数据下的运行效率,用 \(\Theta\) 记号来表示。
diff --git a/chapter_data_structure/basic_data_types/index.html b/chapter_data_structure/basic_data_types/index.html index 52fbd6fc9..39fad384d 100644 --- a/chapter_data_structure/basic_data_types/index.html +++ b/chapter_data_structure/basic_data_types/index.html @@ -3645,7 +3645,8 @@图 12-8 展示了构建二叉树的递归过程,各个节点是在向下“递”的过程中建立的,而各条边(引用)是在向上“归”的过程中建立的。
如图 12-15 所示,汉诺塔问题形成一棵高度为 \(n\) 的递归树,每个节点代表一个子问题,对应一个开启的 dfs()
函数,因此时间复杂度为 \(O(2^n)\) ,空间复杂度为 \(O(n)\) 。
图 14-7 展示了以上代码的动态规划过程。
@@ -3998,8 +3998,8 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]无后效性是动态规划能够有效解决问题的重要特性之一,其定义为:给定一个确定的状态,它的未来发展只与当前状态有关,而与过去经历的所有状态无关。
@@ -4303,8 +4303,8 @@ dp[i, 2] = dp[i-2, 1] + dp[i-2, 2]在上面的案例中,由于仅需多考虑前面一个状态,因此我们仍然可以通过扩展状态定义,使得问题重新满足无后效性。然而,某些问题具有非常严重的“有后效性”。
图 14-14 给出了以 \(dp[2, 1]\) 为根节点的递归树,其中包含一些重叠子问题,其数量会随着网格 grid
的尺寸变大而急剧增多。
从本质上看,造成重叠子问题的原因为:存在多条路径可以从左上角到达某一单元格。
@@ -4223,8 +4223,8 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]如图 14-15 所示,在引入记忆化后,所有子问题的解只需计算一次,因此时间复杂度取决于状态总数,即网格尺寸 \(O(nm)\) 。
@@ -4551,8 +4551,8 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]图 14-16 展示了最小路径和的状态转移过程,其遍历了整个网格,因此时间复杂度为 \(O(nm)\) 。
数组 dp
大小为 \(n \times m\) ,因此空间复杂度为 \(O(nm)\) 。
如图 14-30 所示,编辑距离问题的状态转移过程与背包问题非常类似,都可以看作填写一个二维网格的过程。
回溯算法通常并不显式地对问题进行拆解,而是将求解问题看作一系列决策步骤,通过试探和剪枝,搜索所有可能的解。
@@ -4136,8 +4136,8 @@ dp[i] = dp[i-1] + dp[i-2]图 14-3 展示了暴力搜索形成的递归树。对于问题 \(dp[n]\) ,其递归树的深度为 \(n\) ,时间复杂度为 \(O(2^n)\) 。指数阶属于爆炸式增长,如果我们输入一个比较大的 \(n\) ,则会陷入漫长的等待之中。
@@ -4452,8 +4452,8 @@ dp[i] = dp[i-1] + dp[i-2]观察图 14-4 ,经过记忆化处理后,所有重叠子问题都只需计算一次,时间复杂度优化至 \(O(n)\) ,这是一个巨大的飞跃。
@@ -4685,8 +4685,8 @@ dp[i] = dp[i-1] + dp[i-2]图 14-5 模拟了以上代码的执行过程。
@@ -4883,8 +4883,8 @@ dp[i] = dp[i-1] + dp[i-2]观察以上代码,由于省去了数组 dp
占用的空间,因此空间复杂度从 \(O(n)\) 降至 \(O(1)\) 。
在动态规划问题中,当前状态往往仅与前面有限个状态有关,这时我们可以只保留必要的状态,通过“降维”来节省内存空间。这种空间优化技巧被称为“滚动变量”或“滚动数组”。
diff --git a/chapter_dynamic_programming/knapsack_problem/index.html b/chapter_dynamic_programming/knapsack_problem/index.html index 060b41eea..f563d7815 100644 --- a/chapter_dynamic_programming/knapsack_problem/index.html +++ b/chapter_dynamic_programming/knapsack_problem/index.html @@ -3826,8 +3826,8 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])如图 14-18 所示,由于每个物品都会产生不选和选两条搜索分支,因此时间复杂度为 \(O(2^n)\) 。
观察递归树,容易发现其中存在重叠子问题,例如 \(dp[1, 10]\) 等。而当物品较多、背包容量较大,尤其是相同重量的物品较多时,重叠子问题的数量将会大幅增多。
@@ -4143,8 +4143,8 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])图 14-19 展示了在记忆化搜索中被剪掉的搜索分支。
@@ -4443,8 +4443,8 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])如图 14-20 所示,时间复杂度和空间复杂度都由数组 dp
大小决定,即 \(O(n \times cap)\) 。
由于当前状态是从左边和上边的状态转移而来的,因此空间优化后应该对 \(dp\) 表中的每一行进行正序遍历。
@@ -4353,8 +4353,8 @@ dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])背包问题是一大类动态规划问题的代表,其拥有很多变种,例如零钱兑换问题。
@@ -4738,8 +4738,8 @@ dp[i, a] = \min(dp[i-1, a], dp[i, a - coins[i-1]] + 1)图 14-25 展示了零钱兑换的动态规划过程,和完全背包问题非常相似。
空间优化处理方式相同,删除硬币维度即可:
@@ -5739,8 +5739,8 @@ dp[i, a] = dp[i-1, a] + dp[i, a - coins[i-1]]设无向图的顶点总数为 \(n\)、边总数为 \(m\) ,则可根据图 9-8 所示的方法实现各种操作。
@@ -5564,8 +5564,8 @@设图中共有 \(n\) 个顶点和 \(m\) 条边,表 9-2 对比了邻接矩阵和邻接表的时间效率和空间效率。
diff --git a/chapter_graph/graph_traversal/index.html b/chapter_graph/graph_traversal/index.html index 52ed1254f..2e282a3e9 100644 --- a/chapter_graph/graph_traversal/index.html +++ b/chapter_graph/graph_traversal/index.html @@ -4000,8 +4000,8 @@代码相对抽象,建议对照图 9-10 来加深理解。
深度优先遍历的算法流程如图 9-12 所示。
除排序之外,在最差情况下,需要遍历整个物品列表,因此时间复杂度为 \(O(n)\) ,其中 \(n\) 为物品数量。
由于初始化了一个 Item
对象列表,因此空间复杂度为 \(O(n)\) 。
你可能会不由地发出感叹:So clean !贪心算法仅用约十行代码就解决了零钱兑换问题。
之所以贪心比穷举更快,是因为每轮的贪心选择都会“跳过”一些状态。
diff --git a/chapter_greedy/max_product_cutting_problem/index.html b/chapter_greedy/max_product_cutting_problem/index.html index 9c3a591da..7559e4146 100644 --- a/chapter_greedy/max_product_cutting_problem/index.html +++ b/chapter_greedy/max_product_cutting_problem/index.html @@ -3840,8 +3840,8 @@ n = 3 a + b图 15-16 最大切分乘积的计算方法
diff --git a/chapter_hashing/hash_algorithm/index.html b/chapter_hashing/hash_algorithm/index.html index 703cdf308..422b999ba 100644 --- a/chapter_hashing/hash_algorithm/index.html +++ b/chapter_hashing/hash_algorithm/index.html @@ -4084,8 +4084,8 @@观察发现,每种哈希算法的最后一步都是对大质数 \(1000000007\) 取模,以确保哈希值在合适的范围内。值得思考的是,为什么要强调对质数取模,或者说对合数取模的弊端是什么?这是一个有趣的问题。
先抛出结论:使用大质数作为模数,可以最大化地保证哈希值的均匀分布。因为质数不与其他数字存在公约数,可以减少因取模操作而产生的周期性模式,从而避免哈希冲突。
@@ -4399,7 +4399,8 @@在许多编程语言中,只有不可变对象才可作为哈希表的 key
。假如我们将列表(动态数组)作为 key
,当列表的内容发生变化时,它的哈希值也随之改变,我们就无法在哈希表中查询到原先的 value
了。
虽然自定义对象(比如链表节点)的成员变量是可变的,但它是可哈希的。这是因为对象的哈希值通常是基于内存地址生成的,即使对象的内容发生了变化,但它的内存地址不变,哈希值仍然是不变的。
diff --git a/chapter_hashing/hash_collision/index.html b/chapter_hashing/hash_collision/index.html index 79d6e1256..674bd12b4 100644 --- a/chapter_hashing/hash_collision/index.html +++ b/chapter_hashing/hash_collision/index.html @@ -4888,8 +4888,8 @@值得注意的是,当链表很长时,查询效率 \(O(n)\) 很差。此时可以将链表转换为“AVL 树”或“红黑树”,从而将查询操作的时间复杂度优化至 \(O(\log n)\) 。
哈希表有三种常用的遍历方式:遍历键值对、遍历键和遍历值。示例代码如下:
我们先考虑最简单的情况,仅用一个数组来实现哈希表。在哈希表中,我们将数组中的每个空位称为「桶 bucket」,每个桶可存储一个键值对。因此,查询操作就是找到 key
对应的桶,并在桶中获取 value
。
从本质上看,哈希函数的作用是将所有 key
构成的输入空间映射到数组所有索引构成的输出空间,而输入空间往往远大于输出空间。因此,理论上一定存在“多个输入对应相同输出”的情况。
下面,我们来尝试推算第二种建堆方法的时间复杂度。
diff --git a/chapter_heap/heap/index.html b/chapter_heap/heap/index.html index 663991c94..17922881c 100644 --- a/chapter_heap/heap/index.html +++ b/chapter_heap/heap/index.html @@ -3967,7 +3967,8 @@下文实现的是大顶堆。若要将其转换为小顶堆,只需将所有大小逻辑判断取逆(例如,将 \(\geq\) 替换为 \(\leq\) )。感兴趣的读者可以自行实现。
@@ -4277,8 +4278,8 @@给定元素 val
,我们首先将其添加到堆底。添加之后,由于 val
可能大于堆中其他元素,堆的成立条件可能已被破坏,因此需要修复从插入节点到根节点的路径上的各个节点,这个操作被称为「堆化 heapify」。
堆顶元素是二叉树的根节点,即列表首元素。如果我们直接从列表中删除首元素,那么二叉树中所有节点的索引都会发生变化,这将使得后续使用堆化进行修复变得困难。为了尽量减少元素索引的变动,我们采用以下操作步骤。
@@ -5136,8 +5137,8 @@总共执行了 \(n\) 轮入堆和出堆,堆的最大长度为 \(k\) ,因此时间复杂度为 \(O(n \log k)\) 。该方法的效率很高,当 \(k\) 较小时,时间复杂度趋向 \(O(n)\) ;当 \(k\) 较大时,时间复杂度不会超过 \(O(n \log n)\) 。
另外,该方法适用于动态数据流的使用场景。在不断加入数据时,我们可以持续维护堆内的元素,从而实现最大的 \(k\) 个元素的动态更新。
diff --git a/chapter_searching/binary_search/index.html b/chapter_searching/binary_search/index.html index d9087d27a..60eefcfe2 100644 --- a/chapter_searching/binary_search/index.html +++ b/chapter_searching/binary_search/index.html @@ -3827,8 +3827,8 @@时间复杂度为 \(O(\log n)\) :在二分循环中,区间每轮缩小一半,循环次数为 \(\log_2 n\) 。
空间复杂度为 \(O(1)\) :指针 \(i\) 和 \(j\) 使用常数大小空间。
@@ -4098,8 +4098,8 @@如图 10-3 所示,在两种区间表示下,二分查找算法的初始化、循环条件和缩小区间操作皆有所不同。
由于“双闭区间”表示中的左右边界都被定义为闭区间,因此通过指针 \(i\) 和指针 \(j\) 缩小区间的操作也是对称的。这样更不容易出错,因此一般建议采用“双闭区间”的写法。
diff --git a/chapter_searching/binary_search_edge/index.html b/chapter_searching/binary_search_edge/index.html index e7a0c05c4..6d4cda6a9 100644 --- a/chapter_searching/binary_search_edge/index.html +++ b/chapter_searching/binary_search_edge/index.html @@ -3737,8 +3737,8 @@那么如何查找最右一个 target
呢?最直接的方式是修改代码,替换在 nums[m] == target
情况下的指针收缩操作。代码在此省略,有兴趣的读者可以自行实现。
我们知道,当数组不包含 target
时,最终 \(i\) 和 \(j\) 会分别指向首个大于、小于 target
的元素。
Tip
diff --git a/chapter_searching/replace_linear_by_hashing/index.html b/chapter_searching/replace_linear_by_hashing/index.html index a13ec1432..ed80ed9d0 100644 --- a/chapter_searching/replace_linear_by_hashing/index.html +++ b/chapter_searching/replace_linear_by_hashing/index.html @@ -3717,8 +3717,8 @@此方法的时间复杂度为 \(O(n^2)\) ,空间复杂度为 \(O(1)\) ,在大数据量下非常耗时。
此方法通过哈希查找将时间复杂度从 \(O(n^2)\) 降至 \(O(n)\) ,大幅提升运行效率。
由于需要维护一个额外的哈希表,因此空间复杂度为 \(O(n)\) 。尽管如此,该方法的整体时空效率更为均衡,因此它是本题的最优解法。
diff --git a/chapter_sorting/bubble_sort/index.html b/chapter_sorting/bubble_sort/index.html index 1645a4480..ddd7cc6f9 100644 --- a/chapter_sorting/bubble_sort/index.html +++ b/chapter_sorting/bubble_sort/index.html @@ -3787,8 +3787,8 @@我们发现,如果某轮“冒泡”中没有执行任何交换操作,说明数组已经完成排序,可直接返回结果。因此,可以增加一个标志位 flag
来监测这种情况,一旦出现就立即返回。
桶排序适用于处理体量很大的数据。例如,输入数据包含 100 万个元素,由于空间限制,系统内存无法一次性加载所有数据。此时,可以将数据分成 1000 个桶,然后分别对每个桶进行排序,最后将结果合并。
diff --git a/chapter_sorting/counting_sort/index.html b/chapter_sorting/counting_sort/index.html index 0609e4d41..bb7589724 100644 --- a/chapter_sorting/counting_sort/index.html +++ b/chapter_sorting/counting_sort/index.html @@ -3846,8 +3846,8 @@计数排序与桶排序的联系
@@ -4286,8 +4286,8 @@快速排序的整体流程如图 11-9 所示。
@@ -4118,8 +4118,8 @@在某些输入下,快速排序可能占用空间较多。以完全有序的输入数组为例,设递归中的子数组长度为 \(m\) ,每轮哨兵划分操作都将产生长度为 \(0\) 的左子数组和长度为 \(m - 1\) 的右子数组,这意味着每一层递归调用减少的问题规模非常小(只减少一个元素),递归树的高度会达到 \(n - 1\) ,此时需要占用 \(O(n)\) 大小的栈帧空间。
@@ -4794,8 +4794,8 @@为什么从最低位开始排序?
diff --git a/chapter_sorting/selection_sort/index.html b/chapter_sorting/selection_sort/index.html index 0928c0645..dd0449ebc 100644 --- a/chapter_sorting/selection_sort/index.html +++ b/chapter_sorting/selection_sort/index.html @@ -3761,8 +3761,8 @@双向队列的实现与队列类似,可以选择链表或数组作为底层数据结构。
diff --git a/chapter_stack_and_queue/queue/index.html b/chapter_stack_and_queue/queue/index.html index c0e5c17c6..f531ac0c2 100644 --- a/chapter_stack_and_queue/queue/index.html +++ b/chapter_stack_and_queue/queue/index.html @@ -3889,7 +3889,8 @@为了实现队列,我们需要一种数据结构,可以在一端添加元素,并在另一端删除元素,链表和数组都符合要求。
@@ -4761,8 +4762,8 @@在数组中删除首元素的时间复杂度为 \(O(n)\) ,这会导致出队操作效率较低。然而,我们可以采用以下巧妙方法来避免这个问题。
@@ -5655,8 +5656,8 @@以上实现的队列仍然具有局限性:其长度不可变。然而,这个问题不难解决,我们可以将数组替换为动态数组,从而引入扩容机制。有兴趣的读者可以尝试自行实现。
两种实现的对比结论与栈一致,在此不再赘述。
diff --git a/chapter_stack_and_queue/stack/index.html b/chapter_stack_and_queue/stack/index.html index 9983c8941..4a044b652 100644 --- a/chapter_stack_and_queue/stack/index.html +++ b/chapter_stack_and_queue/stack/index.html @@ -3790,7 +3790,7 @@/* 初始化栈 */
-// Javascript 没有内置的栈类,可以把 Array 当作栈来使用
+// JavaScript 没有内置的栈类,可以把 Array 当作栈来使用
const stack = [];
/* 元素入栈 */
@@ -3815,7 +3815,7 @@
/* 初始化栈 */
-// Typescript 没有内置的栈类,可以把 Array 当作栈来使用
+// TypeScript 没有内置的栈类,可以把 Array 当作栈来使用
const stack: number[] = [];
/* 元素入栈 */
@@ -3900,7 +3900,8 @@
为了深入了解栈的运行机制,我们来尝试自己实现一个栈类。
@@ -4648,8 +4649,8 @@使用数组实现栈时,我们可以将数组的尾部作为栈顶。如图 5-3 所示,入栈与出栈操作分别对应在数组尾部添加元素与删除元素,时间复杂度都为 \(O(1)\) 。
@@ -5240,8 +5241,8 @@支持操作
diff --git a/chapter_tree/array_representation_of_tree/index.html b/chapter_tree/array_representation_of_tree/index.html index 04fec1158..1c9d48dad 100644 --- a/chapter_tree/array_representation_of_tree/index.html +++ b/chapter_tree/array_representation_of_tree/index.html @@ -4636,8 +4636,8 @@二叉树的数组表示主要有以下优点。
diff --git a/chapter_tree/binary_search_tree/index.html b/chapter_tree/binary_search_tree/index.html index a1c3b2f5a..e11675817 100644 --- a/chapter_tree/binary_search_tree/index.html +++ b/chapter_tree/binary_search_tree/index.html @@ -3908,8 +3908,8 @@给定一个待插入元素 num
,为了保持二叉搜索树“左子树 < 根节点 < 右子树”的性质,插入操作流程如图 7-18 所示。
与查找节点相同,插入节点使用 \(O(\log n)\) 时间。
如图 7-22 所示,二叉树的中序遍历遵循“左 \(\rightarrow\) 根 \(\rightarrow\) 右”的遍历顺序,而二叉搜索树满足“左子节点 \(<\) 根节点 \(<\) 右子节点”的大小关系。
diff --git a/chapter_tree/binary_tree/index.html b/chapter_tree/binary_tree/index.html index 3979a4139..023e5b1a1 100644 --- a/chapter_tree/binary_tree/index.html +++ b/chapter_tree/binary_tree/index.html @@ -4043,7 +4043,8 @@与链表类似,在二叉树中插入与删除节点可以通过修改指针来实现。图 7-3 给出了一个示例。
@@ -4167,7 +4168,8 @@Note
diff --git a/chapter_tree/binary_tree_traversal/index.html b/chapter_tree/binary_tree_traversal/index.html index 9c2083aec..6e174f733 100644 --- a/chapter_tree/binary_tree_traversal/index.html +++ b/chapter_tree/binary_tree_traversal/index.html @@ -3905,8 +3905,8 @@Tip
diff --git a/en/chapter_array_and_linkedlist/array/index.html b/en/chapter_array_and_linkedlist/array/index.html index 47ed49d41..418c00819 100644 --- a/en/chapter_array_and_linkedlist/array/index.html +++ b/en/chapter_array_and_linkedlist/array/index.html @@ -1384,13 +1384,13 @@The "array" is a linear data structure that stores elements of the same type in contiguous memory locations. We refer to the position of an element in the array as its "index". The following image illustrates the main terminology and concepts of an array.
+An "array" is a linear data structure that operates as a lineup of similar items, stored together in a computer's memory in contiguous spaces. It's like a sequence that maintains organized storage. Each item in this lineup has its unique 'spot' known as an "index". Please refer to the Figure 4-1 to observe how arrays work and grasp these key terms.
Figure 4-1 Array Definition and Storage Method
There are two ways to initialize arrays depending on the requirements: without initial values and with given initial values. In cases where initial values are not specified, most programming languages will initialize the array elements to \(0\):
+Arrays can be initialized in two ways depending on the needs: either without initial values or with specified initial values. When initial values are not specified, most programming languages will set the array elements to \(0\):
Elements in an array are stored in contiguous memory locations, which makes it easy to compute the memory address of any element. Given the memory address of the array (the address of the first element) and the index of an element, we can calculate the memory address of that element using the formula shown in the following image, allowing direct access to the element.
+Elements in an array are stored in contiguous memory spaces, making it simpler to compute each element's memory address. The formula shown in the Figure below aids in determining an element's memory address, utilizing the array's memory address (specifically, the first element's address) and the element's index. This computation streamlines direct access to the desired element.
Figure 4-2 Memory Address Calculation for Array Elements
-As observed in the above image, the index of the first element of an array is \(0\), which may seem counterintuitive since counting starts from \(1\). However, from the perspective of the address calculation formula, an index is essentially an offset from the memory address. The offset for the first element's address is \(0\), making its index \(0\) logical.
+As observed in the above illustration, array indexing conventionally begins at \(0\). While this might appear counterintuitive, considering counting usually starts at \(1\), within the address calculation formula, an index is essentially an offset from the memory address. For the first element's address, this offset is \(0\), validating its index as \(0\).
Accessing elements in an array is highly efficient, allowing us to randomly access any element in \(O(1)\) time.
As shown in the image below, to insert an element in the middle of an array, all elements following the insertion point must be moved one position back to make room for the new element.
+Array elements are tightly packed in memory, with no space available to accommodate additional data between them. Illustrated in Figure below, inserting an element in the middle of an array requires shifting all subsequent elements back by one position to create room for the new element.
Figure 4-3 Array Element Insertion Example
-It's important to note that since the length of an array is fixed, inserting an element will inevitably lead to the loss of the last element in the array. We will discuss solutions to this problem in the "List" chapter.
+It's important to note that due to the fixed length of an array, inserting an element will unavoidably result in the loss of the last element in the array. Solutions to address this issue will be explored in the "List" chapter.
Similarly, as illustrated below, to delete an element at index \(i\), all elements following index \(i\) must be moved forward by one position.
+Similarly, as depicted in the Figure 4-4 , to delete an element at index \(i\), all elements following index \(i\) must be moved forward by one position.
Figure 4-4 Array Element Deletion Example
-Note that after deletion, the last element becomes "meaningless", so we do not need to specifically modify it.
+Please note that after deletion, the former last element becomes "meaningless," hence requiring no specific modification.
Overall, the insertion and deletion operations in arrays have the following disadvantages:
+In summary, the insertion and deletion operations in arrays present the following disadvantages:
In most programming languages, we can traverse an array either by indices or by directly iterating over each element:
+In most programming languages, we can traverse an array either by using indices or by directly iterating over each element:
To find a specific element in an array, we need to iterate through it, checking each element to see if it matches.
-Since arrays are linear data structures, this operation is known as "linear search".
+Locating a specific element within an array involves iterating through the array, checking each element to determine if it matches the desired value.
+Because arrays are linear data structures, this operation is commonly referred to as "linear search."
In complex system environments, it's challenging to ensure that the memory space following an array is available, making it unsafe to extend the array's capacity. Therefore, in most programming languages, the length of an array is immutable.
-To expand an array, we need to create a larger array and then copy the elements from the original array. This operation has a time complexity of \(O(n)\) and can be time-consuming for large arrays. The code is as follows:
+In complex system environments, ensuring the availability of memory space after an array for safe capacity extension becomes challenging. Consequently, in most programming languages, the length of an array is immutable.
+To expand an array, it's necessary to create a larger array and then copy the elements from the original array. This operation has a time complexity of \(O(n)\) and can be time-consuming for large arrays. The code are as follows:
Arrays are stored in contiguous memory spaces and consist of elements of the same type. This approach includes a wealth of prior information that the system can use to optimize the operation efficiency of the data structure.
+Arrays are stored in contiguous memory spaces and consist of elements of the same type. This approach provides substantial prior information that systems can leverage to optimize the efficiency of data structure operations.
However, continuous space storage is a double-edged sword, with the following limitations:
Arrays are a fundamental and common data structure, frequently used in various algorithms and in implementing complex data structures.
+Arrays are fundamental and widely used data structures. They find frequent application in various algorithms and serve in the implementation of complex data structures.
As shown below, deleting a node in a linked list is also very convenient, requiring only the change of one node's reference (pointer).
@@ -1997,8 +1997,8 @@Accessing nodes in a linked list is less efficient. As mentioned earlier, any element in an array can be accessed in \(O(1)\) time. However, in a linked list, the program needs to start from the head node and traverse each node sequentially until it finds the target node. That is, accessing the \(i\)-th node of a linked list requires \(i - 1\) iterations, with a time complexity of \(O(n)\).
@@ -2154,8 +2154,8 @@Traverse the linked list to find a node with a value equal to target
, and output the index of that node in the linked list. This process also falls under linear search. The code is as follows:
The following table summarizes the characteristics of arrays and linked lists and compares their operational efficiencies. Since they employ two opposite storage strategies, their properties and operational efficiencies also show contrasting features.
diff --git a/en/chapter_array_and_linkedlist/list/index.html b/en/chapter_array_and_linkedlist/list/index.html index fbb3e7430..fa90e0bf3 100644 --- a/en/chapter_array_and_linkedlist/list/index.html +++ b/en/chapter_array_and_linkedlist/list/index.html @@ -3307,8 +3307,8 @@Does storing arrays on the stack versus the heap affect time and space efficiency?
+Q: Does storing arrays on the stack versus the heap affect time and space efficiency?
Arrays stored on both the stack and heap are stored in continuous memory spaces, and data operation efficiency is essentially the same. However, stacks and heaps have their own characteristics, leading to the following differences.
Why do arrays require elements of the same type, while linked lists do not emphasize same-type elements?
+Q: Why do arrays require elements of the same type, while linked lists do not emphasize same-type elements?
Linked lists consist of nodes connected by references (pointers), and each node can store data of different types, such as int, double, string, object, etc.
In contrast, array elements must be of the same type, allowing the calculation of offsets to access the corresponding element positions. For example, an array containing both int and long types, with single elements occupying 4 bytes and 8 bytes respectively, cannot use the following formula to calculate offsets, as the array contains elements of two different lengths.
-After deleting a node, is it necessary to set P.next
to None
?
Q: After deleting a node, is it necessary to set P.next
to None
?
Not modifying P.next
is also acceptable. From the perspective of the linked list, traversing from the head node to the tail node will no longer encounter P
. This means that node P
has been effectively removed from the list, and where P
points no longer affects the list.
From a garbage collection perspective, for languages with automatic garbage collection mechanisms like Java, Python, and Go, whether node P
is collected depends on whether there are still references pointing to it, not on the value of P.next
. In languages like C and C++, we need to manually free the node's memory.
In linked lists, the time complexity for insertion and deletion operations is O(1)
. But searching for the element before insertion or deletion takes O(n)
time, so why isn't the time complexity O(n)
?
Q: In linked lists, the time complexity for insertion and deletion operations is O(1)
. But searching for the element before insertion or deletion takes O(n)
time, so why isn't the time complexity O(n)
?
If an element is searched first and then deleted, the time complexity is indeed O(n)
. However, the O(1)
advantage of linked lists in insertion and deletion can be realized in other applications. For example, in the implementation of double-ended queues using linked lists, we maintain pointers always pointing to the head and tail nodes, making each insertion and deletion operation O(1)
.
In the image 'Linked List Definition and Storage Method', do the light blue storage nodes occupy a single memory address, or do they share half with the node value?
+Q: In the image "Linked List Definition and Storage Method", do the light blue storage nodes occupy a single memory address, or do they share half with the node value?
The diagram is just a qualitative representation; quantitative analysis depends on specific situations.
Is adding elements to the end of a list always O(1)
?
Q: Is adding elements to the end of a list always O(1)
?
If adding an element exceeds the list length, the list needs to be expanded first. The system will request a new memory block and move all elements of the original list over, in which case the time complexity becomes O(n)
.
The statement 'The emergence of lists greatly improves the practicality of arrays, but may lead to some memory space wastage' - does this refer to the memory occupied by additional variables like capacity, length, and expansion multiplier?
+Q: The statement "The emergence of lists greatly improves the practicality of arrays, but may lead to some memory space wastage" - does this refer to the memory occupied by additional variables like capacity, length, and expansion multiplier?
The space wastage here mainly refers to two aspects: on the one hand, lists are set with an initial length, which we may not always need; on the other hand, to prevent frequent expansion, expansion usually multiplies by a coefficient, such as \(\times 1.5\). This results in many empty slots, which we typically cannot fully fill.
-In Python, after initializing n = [1, 2, 3]
, the addresses of these 3 elements are contiguous, but initializing m = [2, 1, 3]
shows that each element's id
is not consecutive but identical to those in n
. If the addresses of these elements are not contiguous, is m
still an array?
Q: In Python, after initializing n = [1, 2, 3]
, the addresses of these 3 elements are contiguous, but initializing m = [2, 1, 3]
shows that each element's id
is not consecutive but identical to those in n
. If the addresses of these elements are not contiguous, is m
still an array?
If we replace list elements with linked list nodes n = [n1, n2, n3, n4, n5]
, these 5 node objects are also typically dispersed throughout memory. However, given a list index, we can still access the node's memory address in O(1)
time, thereby accessing the corresponding node. This is because the array stores references to the nodes, not the nodes themselves.
Unlike many languages, in Python, numbers are also wrapped as objects, and lists store references to these numbers, not the numbers themselves. Therefore, we find that the same number in two arrays has the same id
, and these numbers' memory addresses need not be contiguous.
The std::list
in C++ STL has already implemented a doubly linked list, but it seems that some algorithm books don't directly use it. Is there any limitation?
Q: The std::list
in C++ STL has already implemented a doubly linked list, but it seems that some algorithm books don't directly use it. Is there any limitation?
On the one hand, we often prefer to use arrays to implement algorithms, only using linked lists when necessary, mainly for two reasons.
std::list
usually occupies more space than std::vector
.std::list
has a lower cache utilization rate. Generally, std::vector
performs better.On the other hand, linked lists are primarily necessary for binary trees and graphs. Stacks and queues are often implemented using the programming language's stack
and queue
classes, rather than linked lists.
Does initializing a list res = [0] * self.size()
result in each element of res
referencing the same address?
Q: Does initializing a list res = [0] * self.size()
result in each element of res
referencing the same address?
No. However, this issue arises with two-dimensional arrays, for example, initializing a two-dimensional list res = [[0] * self.size()]
would reference the same list [0]
multiple times.
In deleting a node, is it necessary to break the reference to its successor node?
+Q: In deleting a node, is it necessary to break the reference to its successor node?
From the perspective of data structures and algorithms (problem-solving), it's okay not to break the link, as long as the program's logic is correct. From the perspective of standard libraries, breaking the link is safer and more logically clear. If the link is not broken, and the deleted node is not properly recycled, it could affect the recycling of the successor node's memory.
-The flowchart below represents this sum function.
@@ -1717,8 +1717,8 @@The while
loop is more flexible than the for
loop. In a while
loop, we can freely design the initialization and update steps of the condition variable.
For example, in the following code, the condition variable \(i\) is updated twice in each round, which would be inconvenient to implement with a for
loop:
Overall, for
loops are more concise, while while
loops are more flexible. Both can implement iterative structures. Which one to use should be determined based on the specific requirements of the problem.
The flowchart below represents this nested loop.
@@ -2299,8 +2299,8 @@The Figure 2-3 shows the recursive process of this function.
@@ -2472,8 +2472,8 @@The execution process of tail recursion is shown in the following figure. Comparing regular recursion and tail recursion, the point of the summation operation is different.
Observing the above code, we see that it recursively calls two functions within itself, meaning that one call generates two branching calls. As illustrated below, this continuous recursive calling eventually creates a "recursion tree" with a depth of \(n\).
@@ -2980,8 +2980,8 @@Observing the above code, when recursion is transformed into iteration, the code becomes more complex. Although iteration and recursion can often be transformed into each other, it's not always advisable to do so for two reasons:
Linear order is common in arrays, linked lists, stacks, queues, etc., where the number of elements is proportional to \(n\):
@@ -2576,8 +2576,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newlineAs shown below, this function's recursive depth is \(n\), meaning there are \(n\) instances of unreturned linear_recur()
function, using \(O(n)\) size of stack frame space:
Figure 2-17 Recursive Function Generating Linear Order Space Complexity
@@ -2903,8 +2903,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newlineAs shown below, the recursive depth of this function is \(n\), and in each recursive call, an array is initialized with lengths \(n\), \(n-1\), \(\dots\), \(2\), \(1\), averaging \(n/2\), thus overall occupying \(O(n^2)\) space:
Figure 2-18 Recursive Function Generating Quadratic Order Space Complexity
@@ -3201,8 +3201,8 @@ O(1) < O(\log n) < O(n) < O(n^2) < O(2^n) \newlineFigure 2-19 Full Binary Tree Generating Exponential Order Space Complexity
diff --git a/en/chapter_computational_complexity/summary/index.html b/en/chapter_computational_complexity/summary/index.html index 22fd7ad4f..276f2873e 100644 --- a/en/chapter_computational_complexity/summary/index.html +++ b/en/chapter_computational_complexity/summary/index.html @@ -1252,12 +1252,9 @@Is the space complexity of tail recursion \(O(1)\)?
+Q: Is the space complexity of tail recursion \(O(1)\)?
Theoretically, the space complexity of a tail-recursive function can be optimized to \(O(1)\). However, most programming languages (such as Java, Python, C++, Go, C#) do not support automatic optimization of tail recursion, so it's generally considered to have a space complexity of \(O(n)\).
-What is the difference between the terms 'function' and 'method'?
+Q: What is the difference between the terms "function" and "method"?
A "function" can be executed independently, with all parameters passed explicitly. A "method" is associated with an object and is implicitly passed to the object calling it, able to operate on the data contained within an instance of a class.
Here are some examples from common programming languages:
Does the 'Common Types of Space Complexity' figure reflect the absolute size of occupied space?
+Q: Does the "Common Types of Space Complexity" figure reflect the absolute size of occupied space?
No, the figure shows space complexities, which reflect growth trends, not the absolute size of the occupied space.
If you take \(n = 8\), you might find that the values of each curve don't correspond to their functions. This is because each curve includes a constant term, intended to compress the value range into a visually comfortable range.
In practice, since we usually don't know the "constant term" complexity of each method, it's generally not possible to choose the best solution for \(n = 8\) based solely on complexity. However, for \(n = 8^5\), it's much easier to choose, as the growth trend becomes dominant.
-Linear order indicates the number of operations grows linearly with the input data size \(n\). Linear order commonly appears in single-loop structures:
@@ -2607,8 +2607,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!Operations like array traversal and linked list traversal have a time complexity of \(O(n)\), where \(n\) is the length of the array or list:
It's important to note that the input data size \(n\) should be determined based on the type of input data. For example, in the first example, \(n\) represents the input data size, while in the second example, the length of the array \(n\) is the data size.
The following image compares constant order, linear order, and quadratic order time complexities.
@@ -3200,8 +3200,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!Biological "cell division" is a classic example of exponential order growth: starting with one cell, it becomes two after one division, four after two divisions, and so on, resulting in \(2^n\) cells after \(n\) divisions.
@@ -3410,8 +3410,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!Figure 2-11 Exponential Order Time Complexity
@@ -3528,8 +3528,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!Exponential order growth is extremely rapid and is commonly seen in exhaustive search methods (brute force, backtracking, etc.). For large-scale problems, exponential order is unacceptable, often requiring dynamic programming or greedy algorithms as solutions.
Figure 2-12 Logarithmic Order Time Complexity
@@ -3804,8 +3804,8 @@ O(1) < O(\log n) < O(n) < O(n \log n) < O(n^2) < O(2^n) < O(n!Logarithmic order is typical in algorithms based on the divide-and-conquer strategy, embodying the "split into many" and "simplify complex problems" approach. It's slow-growing and is the most ideal time complexity after constant order.
The image below demonstrates how linear-logarithmic order is generated. Each level of a binary tree has \(n\) operations, and the tree has \(\log_2 n + 1\) levels, resulting in a time complexity of \(O(n \log n)\).
@@ -4161,8 +4161,8 @@ n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1Figure 2-14 Factorial Order Time Complexity
@@ -4504,8 +4504,8 @@ n! = n \times (n - 1) \times (n - 2) \times \dots \times 2 \times 1It's important to note that the best-case time complexity is rarely used in practice, as it is usually only achievable under very low probabilities and might be misleading. The worst-case time complexity is more practical as it provides a safety value for efficiency, allowing us to confidently use the algorithm.
From the above example, it's clear that both the worst-case and best-case time complexities only occur under "special data distributions," which may have a small probability of occurrence and may not accurately reflect the algorithm's run efficiency. In contrast, the average time complexity can reflect the algorithm's efficiency under random input data, denoted by the \(\Theta\) notation.
diff --git a/en/chapter_data_structure/summary/index.html b/en/chapter_data_structure/summary/index.html index 901c41c58..33c3a5b7e 100644 --- a/en/chapter_data_structure/summary/index.html +++ b/en/chapter_data_structure/summary/index.html @@ -1242,23 +1242,15 @@Why does a hash table contain both linear and non-linear data structures?
+Q: Why does a hash table contain both linear and non-linear data structures?
The underlying structure of a hash table is an array. To resolve hash collisions, we may use "chaining": each bucket in the array points to a linked list, which, when exceeding a certain threshold, might be transformed into a tree (usually a red-black tree). From a storage perspective, the foundation of a hash table is an array, where each bucket slot might contain a value, a linked list, or a tree. Therefore, hash tables may contain both linear data structures (arrays, linked lists) and non-linear data structures (trees).
-Is the length of the char
type 1 byte?
Q: Is the length of the char
type 1 byte?
The length of the char
type is determined by the encoding method used by the programming language. For example, Java, JavaScript, TypeScript, and C# all use UTF-16 encoding (to save Unicode code points), so the length of the char type is 2 bytes.
Is there ambiguity in calling data structures based on arrays 'static data structures'? Because operations like push and pop on stacks are 'dynamic.'
+Q: Is there ambiguity in calling data structures based on arrays "static data structures"? Because operations like push and pop on stacks are "dynamic".
While stacks indeed allow for dynamic data operations, the data structure itself remains "static" (with unchangeable length). Even though data structures based on arrays can dynamically add or remove elements, their capacity is fixed. If the data volume exceeds the pre-allocated size, a new, larger array needs to be created, and the contents of the old array copied into it.
-When building stacks (queues) without specifying their size, why are they considered 'static data structures'?
+Q: When building stacks (queues) without specifying their size, why are they considered "static data structures"?
In high-level programming languages, we don't need to manually specify the initial capacity of stacks (queues); this task is automatically handled internally by the class. For example, the initial capacity of Java's ArrayList is usually 10. Furthermore, the expansion operation is also implemented automatically. See the subsequent "List" chapter for details.
-1JQLzG2X~10YYJq-57YSNujAYdZYzM*=vLGFT!ijxLucUEi>gZX zR(L3@l0IOaURp(r%eO_}IF+E`wBK4NH&GbLlW@u|C9MDsEMa=c@P1+qpy z?Rp)bS%QLC>*QTJPJ(P(=NHgZ!)f&`?Yw_(*3F~hWaR*SXi}ThF(zcljRPcD^u^KN z0apB1gj)FbCz%)}52Zel4YqzL9#!Vv&xXn0P-^u4ROr|}I>jxRVdw_vY81)UN>h$R z!7-C)Kdjp8ZSKJSQC$8eCNN*tf*N#JYOWyyB2M4E1>R5j2lom9<`$W_2(}(`y&xy7 zE1S}qwyIHxPicJ05pKk62AR2m3mVWFoO%^S-;>Nw=(U1x)NI_i9Dqrj?YcHtApw2# z@rplE=%dIAIHCz8jnN*+e#soU6y&3nE&gQ9gh-S4NvEy@x7@FQg--RjQEDih>|p_C z>!@aj;ecJXjynZd!#9(MzgbRWYg!LFv=x4bdN5KW6yKO0=EP$nSbHdCHT!50YlRG0 zN55gOfGYQ=(~uEJ1(t!U$tT-52!gO;KQLvFSOKm3c=LJI*M#uWyp)_e3=5K>rWdvu zIJ<_fnE$M+V7N>{8+~ZQ$d%gfr_kEYJYV8DlJ#C8wHo(?TaL%@q$5dyKHmGa43B#@ zER>eyJZuF2F%!fm*{4 Tn^ks}yucnWyiS@ d)T9Zc6)ZFYJ%ipcG7+5W M9ZY|QoTCuX&-92 z$kG$YRpA)9vkh$-gSQ}4et@~jsOcA={GBd#&ug5Q`?#s`ecX_$CtyXCJ`d2q=4Af# znTSG7DpuBA _uJXiFZzA z`0GYY&cRO%KNC6kaw2%DT!EX@B^jT4am9Y59B*0>d$YG@!P(!lkqkTs-cE9mf?M?} z={71*3%xLpo`pPQxB2l4b> yB;ktoO_KJ3<&DZ+eliDo#9@dVM{gk2S>*$_7c) z=Xi|R5q&A <8HIr1H%bpjmi$J$DloFAWvfur+sHJBFM9|JkJj1+C@Rm%9nH)> zoz0l3@%%#3fU;F;RvQ^mfE&bxjBaMrDua#oEFhy=HKD~pzh`)3{@4`cOsEUu5~4H- znU-~0W&6J+CgBhUt6z`SrXQp9m?eb)9J6fYf&HCqC+`&*Zn%0h$p9LqM&T&m&~IfV zo9j+0$OZ6|U5h23Crv$C!0}6`sK1s^jwWp&SIcEZDgL_y*zm+>UuLYNg%4QKrR1OY zHnS1uBjnB3|0)zv)36#oN=-zzN+Qr(Z0JP5gfkKi7mTE6l-FYhS}JAtk7Xo* s?y6S) Tn}FVsClUgm?(S`;RUE;OCkgi;(gFzMr1>^JfI)7 z4(URM9$;*SA@4wHQ+0r2$qzGa?>oc@+;;kj;wZ}k7#=+1 k_iTbNAdwB237S+VRdA)7-MfzKgekk%%X8@=Tt|?&DXin zKduT@ksoI9f 622FFaB06Q`YFY9b?&32g;-I1^d{K&GsWQQ`$A)s=-W%DF5x{ d@_=&UXv4 zq|4-?fF9cjm2?D1<4DV65AO%$fC*~@mu=iy0k53WRjF4oG`iiR{N*4yAzZoh72YyK z4){U?(MQ;?0JKCbJ#kE%i41>;61uAOTOO5^uR|f>VuW5DBq3uK+aN}A5)kZ 79hQYHdMSXY2Agh8E3 zlZT9Ax!e&7jXZkH;M{{mvd+ZPUlC|Z(y=JO( @`&R|=5s4x@NPvPEnFZGOwEw-rZ=kl{A)e^BU2Dtx{^~4c64Kg z7Jv2&m0pu_IQcQjl`RvFozLB;GMJHSB`HGB_?8jO<6&9=;@d`S3d~XY=*2N_ ?o9T2E_bvv &Z7Pq{$Ukz9yk?mO%hK{oLCASc8oVre!NG03f+_%x&y`VrQxfEs(fWojV` z8NVk-G;YVqDRQL|Gx5`b^3nzzN~&iCYwDCW-frdvM}8X|dRdOZOgB*a6|wOSMZ=9l zj0;qjUX4dp@ASPs1T0bC{azm3`AKsadTopn7tO}{Zw+~s^fne)kVHryOhFwuKhPrX zkkRGOZZllAzkiHSFfid+vl&?z`-Dk5!@SVuh@R+e7SIN<2$&_TfAOV4kdYatM<7>J zy>W($d;VOHyJe`|_h({tWPf-pCu`oj&5V#dax^Z(*f;SOjeS57MWnTHkUIV);^#%F z6AhP!2*{;ziJ}~er{Ac0IPN{6*1(EInG<3U{V;Og^dOuDz9hwC&E|Z4Rk6P~`g1H% zdX_jKB>?sb)(v&l6> T@&57$tm3x4{WXj)O+9q9F7tp|824z#_%Gi8m!7>^W|H;YdFs z)h5YqH2gJDzQg ?eIvu)-S| z<+0FYvK<+7&7?0A9rn7uz}jea>HHPSIpKU!n2PHfw#R`BNdE1MPSk$&Rtn#|p=kR- z=Heiq643cD@EGyR=*$a-{Hx<(&>lFx-;dZ*r|($8&AN17nqKl|gfwCdIv}s%>_Ws* zF_%9&+5rwe3v&-H$V*EU2|)M~_HwIGVlOFX)-W<`_0|Mf0_JX(AP*`?K=QwUmd|A# zV)#DD7&rSnBE&xN7nHOVzy#wftF#I1ln9<(vI5MWp9=6ID-wr!AlZs0U}tw`q8ue~ z1$-Q=x?#&8$6Tw59JV9%Zy)EF_d#nU4}c?rSC@|4na5k}Hpvmf1>MR7*}PVOy6533 zr4=EfQ+z~1H&91$yY@1SaDqR6#W^*Y$mp*;uXhra{8|&i5Q^r D;C8O4a?7?A{-4xmX&<=_ zSBRb&J^KSzifFBUcvqNYz-G76-GyqzJu_*0X`CE@bC?bFs8fB^DH>BjW<8C* F4reVsVsKQ+qCU(GEuSCdLdHJx%D*|GU93H5A z=}Jr|ayxQwl3{vh`Z KMD6fd3rtWRc&f+P4K$Y=g1~#u#Iwb zeH}Kc{naXzghY!S8@G>x>>>93ETnjFU_fG=1DtO;M0a|Mk}c>9O{H>wH}(5>KI@*; zbXP`UG(bY+jvW>d{}|pN@e;6Cd;GO}j@{0KJ77$w=`#m7(Z|(!>TR=(POyb(m)=od z{;m7n=j$$rQ6*jzWd*br8!^ld&P$!1+PWb-% Nm$U z!t4qsq%$fSpa9-S Qsa)aD|ZxhoAY<~51%nH(A;y;sJHOMMV$swJ&dUIOMLP@Pt;(L5j5|Bid2!u zOl@n>-}9;aj+LunO7UGe{!~jdU7VT0{PPGQF ?x8nzxw`&1qq!E;@ z%x}KqF3zJ3vy(*Zg73(*b8_Nb(S}dC%9q%VL|*373tB|+Nm1&Hm2hRucVrvh*|4s5 z2yrUsSTIMtd(-!Bk;}%5NbY?oM^(NlfRyjiW}u%Q&v9`Wqkym9xtC3vFw6BdZbXJS zc;O|qzxJgFt?0NzLzOFzS!hRuIpZ{-B)Qvfz;9S~J#_NRVWl8F^6pRvj~Srr4Kb>- zH%KVwv`mP}eGk#|sng>~U(G9UWl=!k%YqinPSKzoS>BQoHu&$w&pumQJO9I&^PPHA zkry0C?dPsw#-&T&Z2cU*tQD8@jp?>Atum#zcQ&y!r4XE%?D-Ij793cQpVZ*U_%vw2A&sr$`De`86`0W^Q&zHUT s|J6GJ#Ha@F z+koRoNir?HXcfFT+rY5Mv1x1t)2QaDK67|ldBKxOhy-s?91#A1IELIpv@R|x5VtdE zM>K?}q5@n{x}LC`p2dZ#DyPm5R1e?Nqy|yaK5n*J3%n#^P{v>(36d_A31mp6%h8VG z$iXmJV0ZT x=|?D>Ru3i$tgMi%)i*<}jm`Q*CtJ0&2{m z&lZV*{djb0S69D}WXcZo#uGi9+(6e-v#+5bvNm-gWN7?Q0I%sIgu9#zFEB}*5hyE! zf?ybVpFwl}DT>p12E~*qlyi4<0Z>Tj;ZMsgpi+$QLDOm*hVrovg_UkX`&NnD_0k!U zard~ZPA?$@#2qhg06QpY#{_p%#QRRwz*MA8c0db!`)v$BDQEGEMS732iN56cLfIcs z8E?S@TeSh{jdv8HF+Y)~pRe#ZP|Y$t_pr07*OJK;f5Qj_3yWd6o>ea9YR}Mvr){6h zV8wF8nbiIx{y&WUeOKtq9g{wyFRyF*=I?ShY4hjegRklCQ9!MndRT`N%)>#}hRFSH z3Lpt(xcwD#S=aL(*cBk<$_&neWO$|$9 sq8xgWR&6!c_W6 z-W+@+om&?Q|7NqAYyfm|92QUR_(cqwLQ+|C3LY?qG3}C-W)a!AxLF4!m*{uLW_MYy zzAoG>2kJ(FX(;?@Xx6oWU(+Xt7N3{EWmrKrB$CfX#fG`?vFNPgsMsv!kWC)c>!NzW zB%{_k-rslclb0@ADpp_gTU5HSG-$C(e3#4{ZJS=sX^2J>mK6AGDKO9vC@~7q>ZBX4 zw|b4HX -CgR`;nn77DE1|ww$&xi5H8s0JzJ*1JfJ&fQ!0Z&uX+M zbO_T(@u&OI3=@;79~E#+SBsr$<3!iEKSy_%1FXI7Brum#tPl>oH_8P0#Uv8cjM~X} z8c(rrpE@%hwHC5(M3cJnMlkv2xM5q2ek QiXQ)&rkuO8ooKG244+1;(4T@7BK5Nc_?${jguu&CnI{uERM4Nj9Ba{*d h9Vh4 zhKv{W5>m)ehLCyAJm!kbvy2(8S!N=V;d^@D-}m|b^}Ww?o@bwZ*4lgRwf9 Nh*M;Ud2(6)o&m^MYzI&=WL zmx2JHmkOVC_E;D2pPuXvhI6aNy3+hq;kstLA*3&%VbCg4;w)7lw9m6N?s7?cp0>7G zU0=Z V)Q%q~tQq_sEy7N1+J+!oGuO!u-^FBR2E;ZN_ z3^4=7WeXJe9Z)rNjxa6)RN~9^D^ff41i-M-r68R@UGbkQx4o?hr%T+#dRV^%yn&1G zp?|e19!VR*0vzssOc!%Qlc-g{^LyIar+r<;I<3l(-D2a#K;q;1D{h9lAm|olpwa62 zq_6j!8C7-T)@nogwXY3y7A>WfDYL$k!2JwpRzjpcLVAnfzw5&7j<`nP4*s|^NXhzk z63nWS4SMh~BHZai6R 1rkk=4QNAms6<%5 z4Uq6F`Tw_j@`T sFqai{^L@lusy=9kv{2HQ>vuK zpB*4YcbvEX&Nm$dL+_Atjvo6u#K_*9Oi9*23i3If2R@Il1g@ifO4d%DSTPwyD}p zM$)dDgd_*6{-lnQR|kw#NI1>3;dE)i=w3jFk_p{W_g@2YM}%%P9XEHuswXN+A3f*y zAsH5@n{^>cx7h2U@sOk$o*Ij+qHt#luDq%G!u08|`E3ghe%7|omD<9zVp=oLgx0kV zp_k4_0n3OdC7)<4SqTU)&K(bs_u3B>Wj!@bcg-6 NkwThSpa~9u&%15Vytf zkL%yHA0SF}PP`F`W=xS>2$T6j11J#1^IPsnUHqmYM)vwWkPC2WT~(aBOp!M}G88iq zUY`p7tVqbx??VwmbFw4O3-lV)?Og=Lq4~!7HRE*wB-ngHqRc@9h}=J;c>QP&9snaI zoLcS;odVJY5mIc-qtM?l-(RK9r3>FFVJ2QkT*SoUF}UEDcQL&syYN?(E^mxlx`Vh( z8;A?alSYiu?eE4Mz!F~l^1U}{V1AodWO`E-A?+j__V}oRbhbiC?s9-ouXpl!pq+Jp z8TADJ4+SoE!m&D!)VbAs6t0)$f$|4p3X8XGY_pz98EF}C0K}od^aU>4k~Ns!-M9+# zcI2XfZJ`Ivn}GS-%L*2l&gadudFJ_Po{eGWv0Zb1gN3vE+!NZg1I+a!RCwN@t49E4 zUZ?L!uOD5T2>+Eclz0JDt+;r;25&bqnelDkuCbW=-&2X@SPmz{bKKjKrzT#1+$$?k z)nCNzzdK<2Qx;mW?@~rXP^p_5V?Rhle{j2Mm|LRH-}`e8)Wd1D_=*B4AKVLExe7E@ z8Giw-3}{_>DZi~~>Tq@}ugfqV*M_!1iDPe=ywAv8{Lg06C(gQkY5s! &PboZw{>To9Xr8%&B0NmC zqcLboL=L>j9ZG;K?YxISKuIq?_OAw(JoH-q*+CtrDLg}%Wgj2rIQ7}|g|R^ueO-cY zwMA4;|K}z!Jb_n)Z(9t8OE;J<^|+(?y<-cQB%_iTI^KT%kVc(4-1`gW)uqH9Nzj}W zd`jh=efjSY){g;=$9W JHVo9U`;?lPd_PXT)3cd>{D(>Y>~VVo4~JHVG~&X8=KrlkYcAA48T5 zrpU_h-R?|OjSjnRv&1MYaGb(5Ob4=*IzT~klSuvet#XDg9RuJK)6HJOJ~lT z>%=X5mD>@}$$M8_x0E@D<-0LyOT+P_htB280(|ED%vfpCv?(sCbQPtSC9F==l+){z zMs%1C1lf00Yb)W|`~$>ySqYEXz91x{;d&iiI&lIIuWYxjtHTd_SO#B1&b0j(55Cw& zGGT|_#bwLu$KU|SQ+CU!{Rvdn6DBH}#-n6k`gsKIOt$S^y6ibcNi0ZRKs~um{qb^2 zUS@C2 jzwRpP2@1O}hL0QU$$j&bCbmNT!SyFqB0tA2k`tGg6tF{~qa;KE zrSdrjEb`XGPH#h9KUkfnt0JRD({ve?k@RQ|k;{6sQ3+KUw5qu?Tp@z7K&%=N2(&s#jk?@!+X?J_5|;MlGo zat{Aw93e+upq21$EhG~FlLQxyEr`)DFDqS$)lNg;o(v~OEDo+LgnoKaZ|m4i$92M` z;ju4Yj$1^PBx&(_`oQ)Iv}T{zPp8E;sO2gAJ&+bC>H%Gb3_%l}ca>RnEUId;)iEiH zCF>MFdiSrVmw!`b#|r9C!K^Z1^;O?T>@%}|-#?&POwlW3+7B-YyfxSu;7z|^-0`?U z--9AsYC o7 @01#DRseHm?Lw8HTq^Xg z3%aM8THBPN>Kk0t_?d0sUA|507e@By$lAASm%A6qjMsP;QxK`N=g&PK+=bH~v@XbI z`)!9MnmgHl18 2b~e z$of+1X$q@e NZp@ObMGK~IvIv7 WMnfA5$3@mbjByL;WbZ_*BehC+GGSH4kA9d7M$=GB|z zNtK61ivGyRM-^Oi!{+&>6v$-50`CuNn<_J54`8IxFHb+OTaFwJ3S}{fdL(5H%Z>Dz zeX+kUGW)BX?56EjxgkSb`KS^dLXmNbMZ=Qf`|W8;+~Pt@M_F9&WET5Xm_+Z3MKp~J z&8{obPVV;o@xJEF2a~zgipSP2AOI+_VJY&^$o^ZcF5XAj2nRZ|FC&AgG&ocB9#?kh zf|}Vuxx|B#$;2;%EA!^n9 3HMJ)-I_!OEdV-lMSyAbH;&=<(FR%Nnc)Hdrn1sE^yC@ zo{;26Unl3@$(t+3EnmdC?WOkobvGrkna`8Fzy*ru)uh8N)-P)yLUqy WP8OZ0*DV`QSxxQjvXgRxqvo{^WZ)W(ww7qrK^(>y1#;G@Z7;mtd%sT090 zgz-y0vqp%LAEdOwt(&AgA1_9Oy^A|iAp&ZD^70vdZFE4uXrsv)v(lPZ8!*5Lz;lug z%pC#4)wGod6Q5MnuLj5rZFq Fs=DXk~o1jxACRVLAWBF~d z)sokm5Z%z0FzxO?JR>10%+y7*x*aP6D<4EnfzOJfct#US#G%W+558Pb9B*$sLyg|q z2t=g`RI_5uPI=phxFWykr;6cQ_>>K8ASvD-*g!FJu#6`VdRk_y1KglTsLy7RrMgZ- zL7P0JZ@y^LVfX9#5Ugrc=og6?{OU7ZQqeG0EX6f7F#I!x3dbmhXLJe!g3AguDArs5 z5q170ivEu%_Ae37e?)mp3eRX|-$M_oYG7}Frf|Fn7vjU&_Qkohg6K1n*_Zw07;#*t zZ5O}T-@s|KFj?v<4HU>bO8|q%K%|b86rrvtadZym>+6er5y)AxI1P_u#qOqgSDbDk zsw*o=DG+iv%?)@Q;V(#F)B8PXvuNZ@+1lbB@fPRpr!izSqzp@>45B(oVPS|%h@OaW z8sC@oNXZsj>p9p=#}&Ie_mURWkk607hcyAW40WWdbxt4EJ!GIOcizwhBv -)88eZF)$T#Bsyl9Ge0%D^K-v3juU8QQ;hL6kg|Eahe87rFsqv d zLpvw^@b($*1RlJV=)3K2FM07BmS1+7T>bh{CEk(Qoz$uRAxP0LJa~+t7VdcUB9V#C zf^>Ikw)(#3Z(V7vt_Q1#_S1~lOxRNza@=7pJWl5lQ M!Vq)SG1 zPR$-ljxVl1p)z$;nE+1vlK5jzdct-xQYhJordhAEPevHVctS=*phtPq@8c>$?zX)j zHXb6~R*oH4asvBu3(V4Abl@JhZ(CK)hH&OP=x72pCHNuj;k2Ns?yQ{|r?w;b!GYR= z=ge@!A}VzV^d8;B5<_|{oi8XOJloo$a+gPCMMp;MBvaw*K6cmyJv}uUi5QkWT|u @rO?iN}b zvtwH+&u(Kpz;8L#_IkX46L^)Np#jv0u!#6T5{#=(0=mzF_|C1G;?;zIkjR_qH!|)6 zkA}VqxT&*aPyU=9d7k`+Eo{9h9;2|hj1#ymRxKz9Dd9TmO>Y&~`yPY|k1i>zz=P3; zPKcVz&McmtHHg9f@>>j8QvbhQR@Z}8s-gsqTYq~rN4X9?1ve`V)8N~4Yb(3v2+roH zbEz}`jwrfQs@efsMJixk27Tk)EPs7gT-IHRBs0OYgiv2_vPqk^3pWw-M)v`=ewfho zd&Ks8DdPLII10e-So7kgjn$Thi}VC+uR%ow1|^}fLcb$a!13!Zd>~lH&$WeGDw~y~ zKk+Dc@L|-F6Yh0k1BiQs(msP3b`lLW;QT?KNlwX#d=~K1myW5bMW)30_>Y70&UMnU zkxzk)95M!}N5ylE<7;-fyBXMyZVjALa9sy6>?`~W>`=lEkMd&RxAkTVu>gH~3S9Un znB$`+_7qdd1s|8z#~?TqU~f7QAt)D&S%*T=O*wo7XAqP;h%|~Nvg;>sq95P{a?UHf z`279Ff#Px$?svGs#Th*NzuNhiP+yMY@{>v4n^p*{)Cpy~fu T~u~cl(s*Q}i(eeRyG{gO6fn@!PkLTu`Dr>9DF-x?(T$#Ff ztJkHlxx$^#ulGaw_@~?E0);3n`L7!ZVeIb58?PhpSBxt+S-*Udsa9z*7#i^6Ma7m} zOiM)MxE5m!TL72I!<#Je+1r{Ar#ljJP>Q4~XU3B?R`L~A4dgeyziXrh^yx868jda< z2$U_cHgFOumx)fI$+K>FM%h*Zp8NqVwJAb_rg3G_GpIZv*qeF_W>Ec93D1azyeB0> zoeF(Y#Y!j 3p}FkB|hDQWyIbV6U6xCZUS)rFjGARtT`8oLu4
DZpXpS8 zdcF^zeBIsbpIx5Z2E&jxJFh?Or5CgsyOu$2+gIk7f<&r5(8-2NYuD>T=?!Z~aKVg1 zE~U7=`2Zpl1%n7VpX=@jF<-v5*udGiI<{Oai?@CS6t5}efB)x@+hf{b#9Zvzxi{Vu zbQT24fe-L%+zrcxjI!L7Fo5b;K>a2oit35n3AF9t{fOQ9(U!49LF5-)bfr^rcxE%c zYlvdQu09x;$CUnwKNz{-DLBYiDolVq?YpiBm!@bNwTZF!yEVp1ST2EfJ!}l~%k~kd z3l*CmYG6o>hExV$B-4HqdJUdm_*1dycTn4}M-ObOW$?Q9=P!wp=v%5*vTcG*dI78q z^EQxL!hsW1zu%l!(dhF(fyOWgp`dLU?5f{MqMGR(6oL|^_~#G00KNt`MHu%gj)#@g z^b%VYP )D`aongr`xi_~C<2Df25^|}dag(9dX-BG;`Uah-; zqaw)A)v!K?kfb{)!4qlh+0@O(I`&ug2X9tXF74 FUK2s;&wQ(2OP&nd%xaJ!dj|qrsRm>_V=3A4M7bTn#90C-R7qg z-Lo+c?4HcE9;wjwtWDCAK0%w|D;>-QieBHv+N3m9M`UNR>X%b>;Gwp?om*?A %WmIQZv*~%6iD9wofyrY^B|;L@g;t%wsL9Cvu2VCFZphEyi#^US z*!6sr`hFz^%f_%5# I8^Yi I ^PMxsWAXj1)SAh^ODKUF-q|TYv7t7Od3xWnf)A82tbYpOzv@9R{5^ zpToL&eWyvZ_~_Y4-@x&(401%M)|b)8gwRbc#J?0Ru%{FWk(IXDe=Dv-EG@8aBod?- z$%Q$m#&;9glA=0;U>R5($V~?JxzFR0w{xHaIu#ZA*{VE_3QdCgf6g8P5dLWV3JiQ; zT@MY&(PjNiK@hVCJVE;sV?&3g+|44mAyyRsO$Qjh6pqp==X}>5$LUL=4r>Ai z?6B?!7=0y=?PN3~8MJ?#^w5g03MRlZ01iC*0(g(NNMqC?Zv >prk#2a3|nJHK11 zAnzi?#m17CqL>1ZJ0)IZB5K9nxfJZQbWLSmyTl%)sou)3UxHlT4|V_X6;bHf=hptr zgQT^FQGNEz_3rxvqG0gQ9nfo@$L9R}1`QdywUM0OJP!+^5b)6F#a}KFFQCP-;5xVu z!Fp#%{xL<;B55DeVQH}mYCw#cAVrI13 ;>inCR{~pztz6t@-YO;oBk=lh^|4aCh4fu+!$bfl5 z6Z%^0YO{~Cky2Q@#qcted`4Oh3to+p7VInXSe{iNX~%Po`W72j8R%+09<7Sv8!vF7 z@i*4t%)Wz?#O^ 1v|GRF#oU2X2I3wJ&Btdqmk3O sE6ROtZTg8opKk~y`E5`1B1-te>h|{aWEvU&>&Un zd&VDW4+b8tek*?v#^-p4MJbb92oHkPOn5xSu3+4~`ESI%FA7(0l;#cpp>Ai34iQMD zrp1X<|{Hav6@{HWxb6-sQg1`W& ?^dOS&^Qkl)YptNtbMk-rrD5yO zM0Pjm+48Tb?b?4*n9}S_qYfgffF{g(f$y53o8Q99y(C`Q+urX|<4jIlg@t7zvYY;$ zgXeK^?-%c8bJ24TiqM&KNaCWr$Y4l3!IgZ>J5c85d8nM~N^bJLf*eT;f;unZxW=#m zhR!jEOSPEM!S<34TaZ4gAFl(&C3?|){4>Q!;N8>WDv>9j?#V`iRC1#p>s>P(Bl-3I zM)7X+G&y`*I0>=$uC;VGZc!R`7<-q1$(%JJgY7XxIGfloD+;pHMfwuX5vPmz=`Wqu z&>9kp$0yrvP{UV*Qz%od;M ^r$Ewes82i4zS%&W}y zN5PPX!T4k?aW@J`!g#P*$XM1rWSv>HdS=Q#l1_$3#@r=*Q=SKPgbU4iF)Q+1oymqb z>Rl?O>+(;ppIwzArNxr*LIY+q=A_!z6-Q~X-xn@8HA|1OLDB|M!S>$izzQCWC0yt# zl}bNV0Ut>oB5C2&|JGBLeZs{R%Jd2g+`eZ~C^27ATWfYFa^JqdDC|Z2+ks+djvVz` z@zOVXZDUq905_2q`{8~S)06RAcNfb2*_SFK?86?`{OFO)bQE`c@Zy!P1*dh(@f_qL zVgG<5t!!XCp5q|URt!rryrKIKr_Q!ijc|6Pi+Go{!fQG#nJBW~R+gmXLt d^pT zjy3KpjeGadvGUhrP?Hx)XJKLhjh+p@ay1z~Mq?>enO*KxaTHiFZC`O-f8y$hQ&r`S z!9wtmIXzeh^Ew15r*h*JoAZJTuPeT#%KunLs3<)Z&ACEj;$sD0ne^+KfCQ7O^_e4q zukaPf$}~hT#JL{Yf#w401G}Zi?~Fl@$E{Wg1{jhZf|FlKs@Ck+E|C4M;aqyrM*^>M z96q!Gm`xyGJ1ggNaF#9sWuiWI{1b7&IDRhiuF7TONxg@vGyFOk&uQjyw>bO-g5)x2 z->y|50`~50T`lu_c=tu@qvbW&@OQ 8Xi8xUJWaytZlzm^Pw{_ zvF7LF&YM{jW(sEKQiUN!n2QIpH_HLfxe)HbO?i{A8!MS6kLvb|1Kf+RWR#ubyNCEK z`}-l;mirH5epiLjSXnsP=;+s}p`JNUZ Y6&5hPab9e1K{R9g7~nn@6Y>V$_zOi>6;s UK3#Us6c*$dI(efICEg7pcp)$GWM8jX=!y^?%OURN1SH`b5Uk+N? zT{#r0_~?SW=@3`iwWA?TUj2cCt()PYk_j3QN-imgynWYo;f}b99F%}9%0UE5xD_f= z^PYhq(8wdcIB-7LHaB_xQ2J?@OqVtdm0;ZPPgV!RmBALsgW)vaJLta4&a$@oXYObj z%!fX6sQ7O9%N1_t_G+c9;Lfn=U}%_M7v-0VWViJ1I=6)RdheWzz8I`v*4+UmP{BP8 z3gjgHHQB>f3QO7^e4qpTq(bc-40_DzZJu{i@^KOb`-&*!A#ewU{H0r*+>o^HpTD0! zEEDadk%7rS%)c`13YWII{!R1VH|@hQ^c@nt-FGqti^6xtF$R6Xm$BdwCBnHpc0tav z7i(lW$@~Ktj~QMQ?j0q4oxS7Cq)~37Cq`u`7Zfs)lVE0ig}YiUTK4bsu4Q${UR|>9 z#XjveS4Z`eC3jF>l?YY0Zk%HpMkno qH}kHHFEw)|3&nJefov6$9^1- zI|e);6vx*TNIM=m-IF5;H)Rm|A2=PM7$gpY_(0CrZie8Dm(Aun)WafWcX`zgyPIxS z8pz!ls9!9J70QoKUBVW1+jr>4D7gBS7C!^ev_MIA1g~GV>198;e92MN{eD@MmcCSv zf~ztWHJNckSM($9d>b(K;{0?^mJCe@WR*57bl!dAk= RGYh{r}}RLDrZvwMbk> Q+5hFdrKY1=q>KytABB}fi~s-t literal 0 HcmV?d00001 diff --git a/en/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png b/en/chapter_stack_and_queue/deque.assets/array_deque_pop_first.png new file mode 100644 index 0000000000000000000000000000000000000000..9d203a63f04834a1445882c207515728179315ff GIT binary patch literal 20773 zcmbrlWmr^E+c3KK%)rpy(k0R%Avu(^G$=U;NOwvO-7VdvD2PadfCG{OO1Fe`2nYxW zf@gf5_x-Nx{P=#H>&&0M=HB +5UEu;H__v-$b? z9~yYh&d&S$`ztFeBO@cfuYRwuudl7Gef|0sy@YOUZOzNe+uGWys;XLAT1rYv%FoY# z_wL=VU%$|3ba8R< PfbQPJnmpUXx{+uPeS zGc&WZvwM1a#>dBBym%omFW=YKS6NxPy1F_uGxPradlM5A85x qq@?)y`OVGEO;1nn?(R-aO(`oY|M>AkPEPL2 zmoEbY1HHYyUS3{WT3V5jk*cbyM@L5}6w2J(+{MMk*x0zHrpCv|CnhFlXJ=<{a4;+^ z?Afzt>Uk6T`uc~5hgMcrsi~=+o}P+|iZtQF-rnAOdwXtfZtQWRZ{EE5b#>FfdJ@?@ z9~>O4uCD&v-(M(Y>_u;ehlhuQgM)bbcwj(4>Zh%u;oY5r;2+w=-tT60OJ=5brdwv4 zeLXyW*ozF#u6Z@AZmxV&$eH@G@r5C3WD8xl@_j=#bG&e<;Lw`qhXK{{k4uNw(_4cd z;<{o_!wokVrY~xe&ysC<62EMX4Wx7@$b%9QYR15qXyF@zY-=< i%j;gep6WfhJjv?c>6%z=`m*9syS%i&X!dGx zXl<}|;_a`(fFEY8AHV% Q*m;$-Qxf^p10%*^!*u=YudgpVE3dDw+-hdd zUq p-BDdRTCv?yanW3Gv$M9F _4y)s*B7{1* ^{IJ>)~a^<9aPAn~18iG^4(-Dp*!%&!Dz zuy{}E+{C4{l&ok5f}aMNKPh*>g{4h7rWvrtQkM2{;p-^c>nxJ}7A|E`Qi#PD8qXOs z%;0}KR-s1yty#SLCH@niX$ycQ?Al$nPTw6nT2IusXyqwV_{VqW+Xr4>c5O*4BjO6; zPUXIUarF4T5V8jp7jmuS3L6Gyzy?L?;Cn>DKiFN=zY7&~@E&uTbr=nT^%X>PgN*d% z!XKxd#SF&oh-C(G#t9`>nZonO`yWV2v^!~P71k=N^f$IKnSvfUk>$frLgLXfI<1{L zzdsb0{iZ>bQK1rAIZ5r?l>^+{z3D<9A|EoY=e(Q1@9XeZ80WBNyw3ntoq~)>u%X!G z<79LQ8oOV7X#bGmZ5yBe;Qopf?zQ_!0V5h-zXlJg7LMGq2I5SB8ZGl5pYFNBk|8_0 z#KUQnIci7k-a}j1$9dX5%0@x$YE_OPL1Yg;x?Sl9;kYbzYLzlN-j12;wC>#ZcQ67U z`L(|0+>a;A<_dR&zCHPc$D_j@c?WS~`~=UQq;{a+S|}|i0Js0?`ZfbARCNPZ=Pt_b z>B!I_|GNY>7HYm>+5tyr81BZrelgMY {DrmV2P zG~2T6c8n!pPRre(Qi%%b3-HbnQ7fCY%m3Y4S zIl80kB*?r-U?o!NC-cuIR5j6q0NDdt%_c1k@4Ed&N$*%ySlAtOs%9v~lM}STm&!o} z<9UOPG=a+IgzE*3Lsv&B!x^@gO6lP(q6DcvJc_7MXm(jm$R}TbDSm6Xz2or>UR=P_ z(|0!iE85aGkJTDU7#VKdju38~rd-5p$0v)BdA{sn$K&Sd{L#0G=Wut7h2c8RZ ?PJ#sD=!ufxI&$!; z8MiA9CX(!15l9Y}4&Su#+Y&7z;+9{p0sxW9@9!4%o&;KOXL^eHhG}EFH+D9dKa)~f zkP|^EovA?PgieFcsF1X11w+$8sT!kd2d)!-!-rayM2@R^t{drl6gtF6Py8oulYPbH z4?hZ-$ RJ ? znj_gzDFJ($!YHMwDd38nmGm9Gh>ZYBxkT^Yj`n# xQ+ ILjVo1L#@J^n5ootlmMuxXE@CnPgj!jCdSMIR!9f@r zSq3*;IpoBv0Zj^2EhmQ8@KTkjKch=d>pX&_qCBW|R^i~$4VuKK2E9(=DCO+hs#(EZ zJ)5cF=0#rA2Yz!-J8{%kWwNg_3v{b3;3xq`lb1+WJ{p2( 8*CLf2q)8PFgx0_ApHG*>fko9mDgsRBVvDlDYiw-TIs0 zC3)PdDv@?i>b%R(`2Vd?2uv31|F !bABovM*?o 6ARbhDQ zmiPGj6Bot!ekZz3eaaH&(i*&*O8ux-{8vDLE;U9lEFHOFco`$bZa>p|dJ#^qD$A4( z$1r8XBmUu?2Bh3xH$c_~IIhy5Pr>JN)_ZP!Zdtd^H2u 3l@_Z?22lJnhq0-eF~_Y$7wr)zkT;}>`Jo{q%}iJ-`<27a);oI!arjZ0cd za;G&^N!-;XkWOo<+mxG{f+S(A#xb`~oNzCQCizgA@md2sNFJ>2ig+o6Tik!nt`|*Z zs!`7F#BZb%6I|czn)65Z0a0k^yvOsomA}&7G`{>Q%KQjSJ21ob{nAApw-j`tvjG&) z;|+R=pv(i6Wo7rU-LEpwtOD_hlj12F6*$8J&f+6^dn8e<0%4|%ug}L^yJTMWFTCQi z0^*i%eI@18i`$iK2cdVr$?s;f{GI!RPtESnxE-@u4qp_p%6Zu^|Kb5;t4^j<7%Snu zCm_UqEh8L+2&6O$W$e?gjaDkdM96S=);9YKv9t{LDSlSP;}*b<{g0l_2)@+NNUx@& zizs7?063U4Ysma6`=yy!Q|jlvrPrW4%WKz{>XwO4v@bT+DRH^_E_=_;dOhF21d4E& zPE}zhO7wX*k6%i5{9|ylCu0Jq|2;5Zi=)0@qI$`CU`uElETU*m9oBY2<`msrqxZT? zA|v``M3rXQM!xQQ0{y3Y0#rs$xXiBI1go#>gy}L(cWB$*-z>g-cSn zZ2$ynC&dnqE{l9!Kw1xt9YAx0W^4h??0~F$uJ=$5r (4>nDqCNVc|i`~^iA)U7uS>P z6Wi}9fbq*rb-ryw-t`2LJ*heDIujqDw3B?r7B>uJchsEgO+zKF8H3JDMV(`~5?FP} zo$t0TkSc*wKyS+jS2fSrg)@xFdS# (#aq0UsA1)9b7hYKKMGd0Mnu9CUphIz$2?A2K>Y;h!*h!{Kq;8jvhs}u;$ z>f_+??^RrcVSUAr9HR^Cgski^%g-mK%P ziP_LOmUa7V+2WuM4>pN?hAc+^PE2XC_B>p%4mBivs8nS9O=2cW4-gXMNTG-3h-f+u zQ3jKkF#Q EkgBO5gj$S5%68rOjyG=DArI z8-$2y#1wl%+-BDLL$*dSQe5wOI7#`t6bUSnglW*M)}q$viiW2|(0aG{qa-To4e;#E zMcB3r^l}fSYyj6`fOl}~9t6%}pAEa4N=O`=eX%MJ3_~#2glwS6F(tVP>7+B0B!8Ns z;VwrH*||7tCX!AKnafRheRnp_^XJ5A^gYAJUyYtBY`e*V%x%)-Ja6?91S_o{fo73p zvwl>QIm2Bluk zCJP~NqirsC62$xQX?1W`R-j-PxK;L3T(7fdk|TI~YA!`_R1W3@t*@I`VJ7n%kjui` zO5oNCQ?2k<-(j+4hiNMDV|NtjyezNu_e0^ORC?T!9ua@N7o7Cw$Tw`S-U&0fK=`ck zAXts +#sU|o%+GlK~V|FOzf+YxTOd-WYQ&| zxxvbd)bhv48#MF{Z%!1zG=*pp=54t$?Eb=3KF4Q&W0zu5x<{CFp^HQJQh&2KBBlJq z8p50N^7H+KLX|MTv%*fPmmm-cGUJp&_AL3>u^in3Mfl4Y5fCfrF1FA}S~~>-q@@Rt7_nRJ`D%9wmh2+m093pxsVmnV;Dq+WpT1 zfa$a;DBpE+UG&@VyJ4@c%cI`+FwOnZu5XwuP`0Aq2Djy5v^8;!-m2Xd{Uq`Biw0!) z97=a4o{lTv+&4^k(i=`e{l295>(Qpn5JztG@O*1-;&w}0LqJw&jyQhF6AqjJUDAQV zT~UFwlk^A%%MTjK?z42cTvAl%KMg>hVR#9nT^=y=JnY4+b#pvPp!7A)k iq}d;?EE~^az)M24E|ds_t}fz7fbfK%_=iOCSlq zP+9x8xVRPnnLm$S104T{3WIVF#J(OXPgcv<%q;tpI!k6VBpizab(M@I=+}sPtNeu+ zzhsCArq&wL0MY$!H!^)kUq~e>H=GP%tMV8)RmGp{T<2QgF#)uEnU#7BIkj231pAlR z_@BRo3wBz!p#MT;kjCGxC5Ya1_|hqH;b-7C4;?Z9@G!-81lzp*x8~kH3iBy-KzN zM;NY%jnSRa;Zfp5ttXOGh1py$b1gtLbrF>rVhL6~f1*3%qi5|J4bfGI^C?5Q@Wu zUg)`!MrjkhQs3A**vtGcD*l||#(iECrxeNRr>0>MfLJXgMyCk$6?@|s8ddG;J;m@9 za+z&@eWS)5zb^5`Zew7^mwK)<=}%gvgQU~F*vEQ2&(1&Pl`{>Nq*JnGz-!>2jZQ<4 zZWR)V?!KNrv|5>kw)w5>Kfh!w@QO+1N4_SVrNk|XCE|))Q^=)VWf@|Cm$J8wiB97p zlLF=7?kS=_Bw27*$HuV^wqp0AVLD21iXL|t>fb#d{xo(w0B>Xv=78vaBs)q`mAdX1 z>1^3Q6oU?Tndipe`^joJkKVRZe*KJP-ROz*OT^s);mTgI9SCJjK@8?pPKv(@$p z@Zx>omk@-r$ymaVYWGnfL$9&D>&D4I^x@BL6plY 1j>4^>|L&w$LX$SUZaMggA z6j@|8zZ#(Y0)s^@J;be{9X71>h_C}*Wj??L(m!lRna}0r4Rf%gSS3p+FtKlaOJqho z821Qp^B(nv&Q T;rglEqleUYht*&Ab`bSx- z;U7k%H+U`hJ?|d|LX{FN*%ppC;X6%`2aG=y`9N~I7RtNxd>K+;?lilQEJhERw11=~ z3`DVzAG)H5K4e7<&)YMTENdw^)Ltq5FU17yHn1S`ALi?)tm%!Ql;7`By9ZcQq!9f+ zCHA2}R1dqLp{7zgOeY8SGCoc<9l*;#8wioAks++ea=1BJ)gWA&|G`xQqSTOYa$?zW zO9XK>Daq5=K?=^We^lB3uS8x!eEF N%yucqdLz+%`K zjy#%I8Ti%DXA0p85l9D}4T9Z->h3>?uEnKdT5H@0Wc 1)?-eD*g8NL_@c=Z{u zSU&SEYWlW+-(CE|)`x;oO0*&MPGO{-r`IX?dpejMy3+fu$?LOp7LfOeILC$KdxW|w z(DxT!+0vm`UY#567E)ZaZu8ZE5=|!q$C2iE(tpD_)Z$)=cXkl;ldQErnJ!4*xn%aP z5eI4u2a=Qc7o3Mu{7sWZJz+E~+MYkou={9zyXab2bMc5090|TYf9p+#*lyLT6@9|> z9)fHhnK oq#6a`@8+M89T+fE(O(!?tp$-yd#> LNX(Q>j5YP+}Bcn2Vn^;M}oIE8LCZ`T0v0wsw9DdB*MyQ#wd+74@j5iQ lm*=?d #D+62)e@q7a7!N8{Cmy~c(P=l?sY8T zb5gaye)J3Dd1>D4;lrhyeVIaDiox=pz{?rmj=#KV9kF9Lxo#A#_$$s?)e=A2v$Zia z{w4hl#Q&$D_7*Y2Wr0bC&2F@3yJ~W&QwqbR1+cp)zuLD(YF=4Qq_FR$oW6MvM)g>; z)Ty~!k{yMehN&`VaxgUurf>ammG7rqRD>9ozDdn)dn|02IMytFN*LkyEe`(LV~bm& z_K(w*K63QT(!*rwc?3ErGm5}~9i_{GaZ{Wbutx8W9oFQ`2Ias-8ej_AcX*&*-FGp9 zDBU@Qa1&eprS766aqAt8$is$%gKd_D3(FZ=Z3TRmBzmr^%~O{SoCQYq&3@hQ(^!HX zLBw{J%RN4@I-?O#Auh%#q-fwVp6t!Xr!m|@a2yUHv(s}Ig6ccPR4gc|ZU*KT6(#q4 zs>r~|7bUM13vrk${8Oh&AHhiU?n4JDk#8{odkctf6@?dStgIEw2Ktz93t-{g+125} zTpu2hj1Xvcwn8KGXd2ytS{g8t{w-wUV;(7DM^_Td>-H@j7|EKcRpM8L8E{6yBo{v} zV5Be<3g}b}JDk!6y- >6xP}LMV6UdwO41$ALpc8Dlmz5jhJpw|;nz5b5P9OJ-7GSpc&S?c(%4Ak;whjO= zRtoDt50P^5T=rKA03q?i%`sKaDD)5N`W>XbF5w3wLA8H`h%F5L`MMpBVbsEbgpnY~ zasEe^{S?%wtjX;B(CGFKhWY(fvbyJu%8Ab|q<>S ~B76*dQJ7TnBUf)Fl8--A@ zOA3uY-?N#4DVHGH@cdB>`DRh1(XANG9b9IEjX!fw8~50dt}&1IkR8M%bSE)zstokA zU~KpJO3q~*Lc#|Z2?b1#H9=FKTWu1HxRi%{xYzBES(}4}u$-sQL!%OwK!xt~I+jYS zxH+~2Tx32D^Fo%FT*bN&Vepql>IN)liof`Y&6{0J$=ccjrAMdGgn3AF98l&m%px}W z)92B!kniI6S&6$}&`DRL%bn|-1end7CShfYAvWwjTrx_Yl9w8pQ8s_`RdJq!Vyk0< zUEBAUyI-Xp3OoUFo6P|`W0*T9YO?8CD1a2f>9|-YHo6cBuPdxH0$w>%*Ri8CUjUxI z@K(%CbwDVBg%?x;a5VrAEYANKks^A?5C{KY@1g9xU@uW>9gIYT1_Ols8yO@2cLe^Q zyHfw>k^kQW>F*bduLWb*ytr>NR0w!p!`uh|SO6a(=XnoJw^&h2vLO9IF%SYjaLDNA zhNu$4+^a$%m*jQ)0+XsgB4`OHNzh@pxT|hxqX*e(M<1tfm@$xB3}gkBDZNM7I?{&2 zEJ}i2#y~>Q>J~5c_(xWrEy{rv*pRtdIZ&G5@pJ#6VN(v5FG0ngEsn5MZXBfcUs#<0 zvT~ToNGn@AbXesUmMV#}>hTwL{27JI+(d#dzr`&9$f5wob8P@CRS HWw>%i*ch#jyi&pwOf$PhKmot!NfmtkSP$EEvhY}$1 z0GVX(Q$bV# KS`K!((krVNl$w9W}@LQajIxu+B3Cr@Gjlv=Oc5 zPS^MSPV;($%Kad??5(t*HB9Qj@SD`-(dhSkG G%6LIi^-b)lT8&fh-Cra<2`89ZZ7zpnV2IOtYn7}oHFpo9`6SSfaxi8`AI zxK E*8ddvkv9r9?(iK~4{jV8 zhOPuw%-j9`avlm@{VMRS@W`YAENRF(VKGtPCUwKl+${&H7~18%ZH3DKZc5{s!f^YC z->lrlMh*cJFVc-poda5%d1zf1P5seIJ+P|h_0yUUi}YPVEt@FHjwja9Z qCR{c9@f^Y zGc!=;_})rdF!~hWYazWd=3>uA$VMswMQRf!3wJhCWPu-B+YwBdrWK)MvqXa(@T`CD z#uUh3{@hk sO=gydmb;b@jc7LWt>i{Vebu*}c_TIduJTx?WKcEX( zhQubqQMLVZ307Fh#x541nQgg3Emt6%9-ZL<*OAh0@reyL2!Gu2Iw;ycMoEaMgg;L) z#C-O?Oc7*EH1PaD_;WrVcZv3QfABxjUI<3QfPApAk)!IRv~$qPOAAr(z`@DjQ xe-33@D1%bI{S#J{=!*&-fOFE}mLSy{ z;Jc8h5$EF**o0{ZrOq M4Z;o9PW_}`~QiSJfGjz1fY^J0$`389RFm>r!-*@;$p z%$acrRPjYiG%T(;00YM6Bs}J&Y^JywrpZZY9eLTSWM06(00Q8}MFzZ4-WYy&58^wq z3ylLDU0W8JKT7adqP1E+<056Jxq;C=^t>SUSbRz^6L!gji@Q5w^bey->77{cGQ=B5 zS}j*K&Sunvqg~|*WyNek#MFdG$%|OXBPEj`0$g|h;%Qc%7~CnXw!ib8p R%F8&%R6Imym}@JEizwFiL~8h|^Q=3jFv$&PcmXE63FG?E zIUcx`*XzqsRp4W_42qUFyy8~bp1} 75FK?%+~Ue z_TXmGMNn(cZPU~{@tWWmd3&;p{^`gKyqs_)96t$e#1*~(*+CN1o5nzF1H${%=y2fM z2ke?RB@1e+2eUc=!|n?&fQVW!bSkwn8p`!L f?o((BY5Ojm zaY`yrGA$};ELH1unQ-^gAICg+1MS`2c qB13!|pyw k;lpEO`%~SvU_Eft(V-+v^_A>*al~gD`xKdZ6 z8sT`GwkOlN`>M=={p1_ZW58IxvRKKsgXn1s8F(f+F`OR(^wi0so;|oy{qx-L8l(u3 zOt4>QRs?(v`4I~GPOdAG;Plckb?O`$!@|M`^t5T<$ o=9kN`Us+&CbG=CDWn>x!nm0Ov3gphbKk5<;o{7fqf3dGa4L z&yVi`=bMH3n?5Hwz)BEBz?^-W1g V^-%#M%$u7LU@{}*dLNfa8y zx*g)S7Gfm_bgz&N1D+3-X@EQe$XhX3sy^yDL+*wxrl+qkfpbX_VjWmpnrLZECl|zY zayMtdv{M@(hT0FaqA0h?P*?lgtF3a_b+~1&*DeujnrPupcz-19SUm9J Bu z>yxZIPbthxv=Z!fm6WM>6-eZ#UY2pOwx_3RDm{$gkEVi?<6$o-k+jl8&9e`Z?66WF zzM!JK5$`;@eB|IDnZCMn`lR6JgS{sqDI!M_`a`6@k |A!~6T;I)T?WBFE9t) c`kM0hxPF6lEa*y;;7NkwRbz?CMvvr%#waN7&Y+_m;U*F_zFKyjp z+6MeT(uFXxV!5BsQNs?m5c{r|p|G(g)dsT?b@fgwO$sz5%JDM6L!yzA&4u)-%;TCw zOW5< eBf1?}tsElMF` z`@tlvk~hyPr^2%)!70t@&zg$a({Oj=BQfFy_oMoA8bt =zGZG(a~@-iPo7&^);s?Wgel5z3kT4LgC7i1`jVV*2CGL<4S#qMnxl@L}pz zJYz!!+iO8~lx_MRHhacZM}Kj8prVwJ-uEznJSxoEznB=R`emIP6*yJ6mxzbVte_lK ztfKvMbp-gT)@#9dS?kYCPj#u~8)d!=Kdx~H=AHRt^NQpFAG8UgQUFD@dj3%5Xg~UM z6s+R>7!VV_^3Fw=6UjbQJD9I6MB5Yh-K%@N2Gl<`CtctytI>b&130nYFg7^;ZOXmB z5JKIZ(U)xeno8|mf$D=_WA`&q*&MIUGV|6PP<(LL+op)v!=vc>wdhu?f3i|l2ZmEr zsZhU@6x_4Z;9zwulMk-vuT%JV84)@JTbiw?;-<=owV9N8zkc8S?`x6{0(y~uPkrd2 z^@GQ6KZ8GfaZP6DD?(8(O#mBX#6cQa@|y58kq)&xDbRoLxG5o7M1QZ8L+SpVJi;VM z`)_<^>4b`a#~m-ZkuP5^%tRXms(k(s4wkss1?qo`nqr_tvr-Ija;!_m?j4L w<$(>ZlYG-p$#j_E=}<&VsU1tU6cb}X$Z$H?fxsXiFhr>Eih840fZ zk6hW4Yx%L^aB5@vsXn>>z}fO2(>-ByYeU!UXmeG|7Ppfti ^_g`^iK)Y`Dmt+a# z@~>0_*t__ZsaPhg?9VqKK<>K#`C$^?>T`ErXcbqe4C-zP#Gjv@5-mRa@!%+U&JZ+U ze+j9=yafAYGvBwsP&?5B4MGG^mSL6Ia;QNkN`$frH|p~d)^Wml&s8Tp$QU%J_@x14 zCpX~;zsAt==MR_0IyV3)9SE_IZ_48ZV@hZNKbn^HA7=G z^d_zdEknmrU}XU=K`p9W1minyH>A;(`Z%l5^e1O=9 E z`2@R4Do4T&=|vE%gxe1I=yZ8zf~Av|L$C5(Zp%HX9740Mb0q|!Imq34c(0f(H)h iaI1^CZxlwP#o@W{jJJOe{If|E8la9BRs$G@O$@M=eBJZ#}zohZa>abhR8*-hrM z4W4esPT1LOCr2+}K6;Nd02{Ag5h?0aaB2e$yCKv*Y=vDy3%iCP6_#%WP(CvHvw^+` zfaH%MV63nBiTMg*(h0A_Wp M=lG3pn1Z-z&aL{YM!4Scd-SUr4G^AS^|P zLZ*F=fMg0K{rkE_=Rcu2!xtmI F6f^pvQLCdhv;Z(ro4+zmDgbwZ3wTv~w5c3;jhT!PBBR z7LZ^8bWRTtK<%$tDzP|wU)iMM7K>VTDjSLMg_QIpi 0OWjxgG zkjH{4H9t=TpqE+^b)lcZ4t39E_T1(yj>C+OOzNyc^U$<4@a(SrQ0_T_WLS}JbtdcZ z+bjoo9pZ}wc=nToMXnIwPnCj#^bT 2DSCm=FH2|FZfp@62-Nr9<`&al3s6r}>%oZUH<6 zG_53lv3&Z(Y@1ck+V!Nv-g8*^dgwaW9Pec*)Q6^c{*VZ8cZJx~Sm!(j {&&mG!zB{k1%qyhEGuR81cJ z$potd8?Ko(2{CeK*n;V-xlVC_qywcSQLBV}AQBajUY~nmOF3bJGF{*LBH@VZRA3 zx1K;Bvpm-)^HFQFk?4)aL54}2ti_5W>JRrSmgMxjr<)Ft0MFZ*6PclB&)TNB72-dC zDdj$o1E-Ztg4i^+s;4@@rLuh!=daclNp~KUR7BU0{QjlU7$}1K6r&NwAE;j)AaA;N zdj|6(12>#&b^#_LWFGN8d`ujUz8jbq^-{Q*4KjB@mrj7pt&ycc{QY8*>%7Q~vTtZ3 zr0Dx#n; K?b}1duY;p95PNZrs`63U!2mA#S zF7xonJR(sNB~BDcW^TL;SP;YN9=aL~UFJGrn)d^v;9nZ}k|>S$9J =@&g=}GWxrFIpAXe7S 2#V_*s)PO zuv$d4{F&u78IO0AsSP)IW3(|>Y-BI~zA);!C#Cy$3fV@b4LZ`kS>h6jcu_atoeVx+ z0CXqRyxf4~=x3gu3vPI(fBw6K2odmpqLAi&l;sV!)6MgDP>OGJ^06B{xv!{(*cQJn z`AXV+4iA3!&?S|2U8a4xmn%s6)o{Z-VQ+Pg54o`vN~Vj#C^cQf#;RT?#SCUi)FQj0 zp|IZ%?$3a$K35|(pEe-M^N{5N7jkE6f(0p*U*>t-1LeB?HPC_y@{XVs?Bjfy)$Hv~ z^4{7EUaMTa7~bJrtaJ@sQrXMXde7Vq-428m93>$#s`uHnD?y^tZ2B(z#jnR>#QQ$U zHuH`dzfk(jibmrN&W0h+KW)~^`jZ@DPF~oQsEb+GRuGhAc (m8Wm%RR!fpfE>-t4G`9=rO3U z8^8a|(gdJvxeI4Wwyf{rVJ*7GxUII|8{RG|RjphdG--N2WcAw>5Ezn(eiru0iz;#) zXx5{cV9IdhaVuw0ln&(dTV9@*dpS#GK}1_8LylPgyNCHS;`ZijDS^d6RSfw`tv|u* z3*Qr6ENMT-jknNOpIByrf_h%9pCk)w59QD6hwm=GKY-3u(LWaY8Os#QzAL&yhzv_4 zgzNZAps2k?S4`&Gx`xwuO|EdA>eh2x?A$vqf!j_mWDY M{OGgK(b3 z2ayeJq~T5%(~iJ6+sg$I#$CvbqLJFXK96~4Oij*lSDkURTlDLatu-$64?MB-$eg8x z9>o*zvA*8(qXT$nX(8r#%Z1l8SsY*e+a9)Hz_2JOIx})VV*p~`*Y;~BtZ~Q_qF2!t z*45y>R34SB2s=0;1gSNFq 1V zX!0M39ku?CL= hU z8SY}DCI`PX=^_jBuxpgavS|cJ?>C;}LyrC{MJhP{@#l|R3}d7q%DQ+v2e@7Fp>Aec zX~z)4!iKhr%YcoKe0|k*f)Y6F{koAP pa;%{%^{u>8|WQwa+dKazr o~XnvqgILlN52~W3*PZDtX?rC zKl={iv{beKZ @kZQ!!!24%6kF1 zKin=+8ypXzTvLF7@(Lpnl8c_`>&Fow q61Yxdnf*3 z`RtnCUv=O{G<`Od0lgU`*TbeXJ5o%46?5e^u0aeJWGQ-z>7V2qgsU0Z!Q>iUGWq~U z`o#C!3wO}QJaj`->a(;pnw c#LJ06n=c*}ke$n$TW^<1Y7W}-i#gP =Dt_?v4IqeAHD(4E=xpP zYeX2{jPMQ-0`Jrgr5Vxs=}Cv+gB?;@IX{)+N}gfZm|)TOV1g1~)_M_obYi?}9KS}S zz3*Q+oK;-FQp^X7KEv!`(jOW$|Bw_V+F-^>5S6|0_MpiBKF~Kg`sF1im^BwLzAHN8 zK}V^<1=Gg7s-zS_X|~)Gs2BTWJy**nhduQZj@cvq31T!Jta;EIO=k!5H)6}@FiUlg zeI*LsA2Kz~tRZ;!HU!XkP>)y2c^h3TbslX0zb4EM;?opE4ZNPBt7AR!$RbfP<|o6I z^L_pOgk^~8JB0!GR!2LmCaPT>QDkDnj>=3_$X>3=Si%k}v#|Z!S)dxir@^_0*`@~1 zE@0B28GD;8v~DL)aTdIOgh^oQi4KtdNEnTa?JlJvyf>SHzJ@lS3EOMs^gL>I0AZQ^ z!lqv)dvHN62-iZkE_m>BHyHPMu!{z(vhX}hK0@ixHDcqr9O}R!0J77o+J&uC7L>b1 z4xMbm9M)x5!;}{*%>r>0Q=)Y^$UD9JIX#gjeIzOXY?Nd*c+gc;Ssf{ndA4Q=8xyBM z{Csn+0~p^cYxTwsHVT3pr>Zl$t1> hM#E|iGAc-??k5F8%06E46Q`9Nh{_SM6!FC_69KdaY( z_=ltZP=99a^87b%$~r;S7*XA|VBnGZ(bOHZHlU;e-MQOF@Ih@2k}fyY9=odhXvA9E z7LXJ92)+Mu2>}dPkOZWIktsdN?dOM&;X2i0nUO@yM18I5N~awUSqRKBI-CdX`>>&p z9h$O^)Wk%F-x`rFr29Xma4PfVxIaWs!J}o&SSuYxRYZc;`>vRNC+C%cJ2RHB*Awpd z4jtsZu(6yFDEJ3yMozf;AZkfvj_TV_>^k*XO#xJ^6A;_z`9f*-4+D20_7!+Gx;yk( zI6>C*e)F@}GtDmJDo0vF@_-kGf+AScV)C|p4cNL@^F3W1%RG##G7=MD(xcb3XuWv7 zQMcK7yw_N|O)cK$M0_!u_g|au$d}cbDhQx>MeLwLd%&_p=ggjZ)ZlP0%h3Ib8%Sjy zv}RZT !u&7-_-E1W>ew&TU8|T-dMH&g5_X)S~Ovj7O{!H>V%mL5T75Kx5P0Md^*1C_OPZr@qXPSf;*68 z5U#lq8Ic$Pqk=$UDY8mR<;xWAtKOUZgn4t{rm|1vYJ=lR@<+)ebw2FQ@L4Y`JaQ VUqc(e0&li9J ^ V0~PrtSg5-2&+ZgvBDO|%e+q6;${z(Xp2KsoW-9f7`{ z6u3|ErNjeNK*BIjlv1acp+IEffJU=S37eia(8MEV!P+31D+HdO4Z;1%i(iE*x72i2 zKqY2o1jLC-;{Bd7ZTQX?yuPd5b^bZ#WkM`jE+xAB-7d%Rk@Y{Na8~`7y-LB}nSSJ( zn6yAVq0nF{*ex}}Iqp{z 7}X@+R=$GO!CT(JF$$b|XnqLXS(oUEQe zACx$*!B5V+6e h`9q{iiP$hcFu|G%NI1vQzOs zjVEbjjV)dYMpI`18dczGM 6$qQbHaoL^8bDDKttbYsx+%BwH%` zGAh}ZEJ $b8|etSn6pGR9H2{3jC&IdC41u*0;^!n?==Q*eoPE-!|*9#>6yip(3 zK~=`lzBypEH@xc2wTi?sWL<&eR3|)I0~HL`qbr{TXOE$s#k*7yEB8=v?;rMwZzwLx z!W+P(=Pq1_0XOmFb_|)DsQr$g@wRdoW?ULa%TW?#BrQI$$9fVl qR-SM-6}*K}8`kPR!;s%bDgqdC0}xTB2yzp95ms)b zXu$!rS=O2Y-tseyi~Y)9&>Xz+DhL&AZRUm)??JM5Do8zuE%t(@KSfNaB5{rA{6}G% zYgy4yUZp+bbk0slEM>LFECLPv3TsipL=bdQgId2xtw$w%;4N<%=<;V Kc7Qe%B*tR$vx6_9D}Tch(mjal;IRez z`PpWB{$3?Zu-(GXKmmP=86Z{_!FcdivXe#7CMHPMMHQiPrr&q)v{2hxIaTDVB969= z z18k4+bQSM8jREFO(z?akZ87f6U~rC|Yzv3$keXTYy&^0>L}$tT6pjM{7BtPW3Na{# z%KT98Rph=Lf+sq05Mfptu!slJET{)Ut-q-xS>D-yGyEs%Kd82b9AM>bG5nj9ydp=Y zZjUR(6X#69#4M=kFSsj28hQvi2O) fv{XPW z25!P)X_tVhn0`AlHKYfze9A~W?5y*xe8m(b1%pm5=Dsgpc8&=%zkXE)D)k$Iq!1SP zfl%?x{}7(&%}@Fbl8{4M^#5J}R{1nXsNd_(2L)f{b~#IsbQ^fdBK-uuX9g15Rcy`# zxG4tg^K>YdjG0=U<)9hiiR|#t7`N@7D{^>Ce$vK<3tp^{gDA+47Jc`7O>Mn2V$2My z(rIuP4u7rUdchvKZ;tB~7WTihyBK-78KwK>Yn2+-zO`y>|I^3o`_+O-pqGo1YpLy; zGsI42$I{k8+h}(0_Kb;Oun_4Ha!u}#DhJV}n)7A52jW9Q>+U3w0z?x_(9M)pLO0Xs zI7-0m#M08Sw82fR0!%i8n`U`06G$O_;-&XjMtwlSN)eu7<*ZWw<9v^Mpue4mUEK*O z5eAyj)8P3kFmI~SeOu!xUM>px0W3J+8(HD-QfFYIZXfao2eCG)PUc+nEuJr2VQeb9 zA=z@zYvS!vT{Q)$M${wV`bdEks4K$ARwoc12gUS4@P(vWaDjtJi+{o(ordvrIfQiD z_aBe5$`(ATphAlW@K&TG8vXx|821+J$H~2wi4rVx+pJmgx-IWRNZr+Ft4CPt3l3t( z3nj{vP{afTw*|5nw2h`uz2U}<_n%_KpYE?+8 CZlKv^n~+<=l*?d=+WKEttGd^`1Q<2beI};j=0eCHeGmTBuj9 LiV(7`3r6E1p2_s4gwP zH^(<=IIhYdpmL=W5g-9o5`bhyAS}%W6)&Gdfjb8O6JSkc9QyVR6+8Dt;CpP1mS E~W) z%1c+Y^}^0dLLZD2h9gSZwz9}2&wWUy0^^hbl$+g4L@w<_7*_C4gH}z*hYP|!R>!Ue zRG!t7VL3oIg@DS%EjgJ35|9rM>LoB%#*U933kBu3QJjNWo-F@&8iBE0!wDW2f$_$2 z$Q2DyY=_dGn4Io~16cl_VMvviuK%H_oiPe?{Zdv#7 iZqbru*v;H8dJ^R*Ax@pPUxgQ@}D#?HgMNyHGpa^3! z4Ogn^>iXmB8@Ol3uVX;K5Zj^t2Q=`JQ8|NCa!-r!SzL`s?hQCJ9LMfrxZLa)_~Aq= zgZEc#RnBy4{w?&? KjC|FzS()wk81XZk7!k#GlG zmsdm##m`%hnp-xC$j#@t_j}HF`Q#aZ81mMb660oNS9~ bjC^Prg5|6Tvf_ok)^LDR|E6lel zKu0A6ShLQa9e zSq)KljbD_%HhoEmQIb}2)47>$JRjs%mKV$o9pzqk0eY1~CVwPby*`=WwRG5B4JrN= zwxor~X#^&Hl;j@ju?rj1;~?HBzG_%wq;D?KIM>ym+DYmZ?pLtN`fOHv!rdf>{R}>H zA93gFNM-r?BLS-4H-o;Hp7SU)xY|A`FNs4=HeG`d$3{HHH^KW6gHMak%uH62U*dZ1&u(Q`u7d7cJqr1;rX0=C?mNs zXh)&t09 go&o2Ze4Dss^puc3m3X%|W^C?LWxou(;uUymD>9 zR#+Y#hR$Wnh*}HdV&uL!gskUFTO@qibxCJ-c;?mZy7RhgOXF?>RTbZB-=%N-DxO@& zGc7+v){%AVUdeRLh2|@NF|;KjmlHQi9LL6odGk0ZhG#|=n?9G8FKKf2W$Eg<89?_R zX! wW&@CD=>@) z+ttR`+fBCn(VKSet*8{;I0O18N1yqkCxzBEHN+xPNINfKP+{pn#0YwWWB&7@K7f9N ze40_s=$fJ8WP}-i5>rpr)33gM8$O0BP__ X$yQ7trHVlR)LkY!pW-$$jdShK}!^}F{7$=#m1 zIdos40~fiUW;i80id!YpJ-z6HJoY(ZJJ7oAI_Zz3&EHGQs4rPS(?W^*20vm#jk%AV z04_@*g`rxf&3$J+wi)>hEOTkUOV)XBo3UHUa93EXiRL_d`u7l`QpMiqjZ7tF6#NQ8 z% -6MoccCJq&2QK({?GWmY^ADo1tSmbARw&r!qZ$)bess5-}S667`ge#h43t z^zN*7J8U=sCeK`*uU73AbL3 r9L#c?-gVk!%~SqyT=3Mz zlSz>WOlC{=oSS^lUY2?z;z)^fbm?o?#r4i(0D68WM$fWAZn9wTX?egyCd|+5Gdn_n z(`GtKst$1Yr257|j4K%mk