算法思路:
递归分前半和后半排序然后合并。
应用:
- 排序
- 求逆序数
注意事项:
- merge函数中更改输入nums。
- line 15的等号决定是否stable sort。
Python代码:
1 | def merge_sort(self, nums: List[int]): |
算法分析:
时间复杂度为O(nlogn),空间复杂度O(n)。
递归分前半和后半排序然后合并。
1 | def merge_sort(self, nums: List[int]): |
时间复杂度为O(nlogn),空间复杂度O(n)。
stack的作用是存储优先级较低的操作数(暂时不能计算)
定义公式
res是作为同一层的临时计算结果,若遇到左括号,res保留在stack中且reset,若遇到右括号,stack的结果还原到res
num也是临时变量负责储存整数
1 | def parenthesis(self, s: str) -> int: |
时间复杂度为O(n),空间复杂度O(n).
两个stack存储优先级较低的字符以及数字,类似于多重括号2*(3*(4))
公式:prev_res+prev_num*[res]
1 | def decodeString(self, s: str) -> str: |
stack=只存加号操作符
核心思想是只有出现运算符,才能计算前一个数[op]num. 所以op和num是记录前一个符号和数字
字符三种类别:空格,数字和运算符
若遇到运算符,就处理四种的op,目标是都要把num压栈,但是op是乘除要计算积或商后才能压栈。压栈后num=0,
若5*6+, char=”+”的时候, prev = “5”, op = “*“, num=”6”.
公式: [prev][op][num][char]
1 | def calculate(self, s: str) -> int: |
Leetcode 046的题目。这里作为知识点归纳。
详见DFS要点,大部分DFS题目涉及
1 | def permute(self, nums: List[int]) -> List[List[int]]: |
1 | public List<List<Integer>> permute(int[] nums) { |
时间复杂度为O(n*n!),空间复杂度O(1)。解大小乘以path长度

i指向4,因为4小于pivot,所以要换到前面去,跟6置换,noSmallerIdx向后移。
1 | def quick_sort(self, nums: List[int]): |
时间复杂度为O(nlogn),空间复杂度O(1)。
选择第k小的数(下标从0开始)
1 | def quick_select(self, nums: List[int], k: int) -> int: |
时间复杂度为O(n),空间复杂度O(1)。
用于原位排序,将相应的元素放入该放的位置直到不满足条件为止
1 | def sort(self, nums: List[int]) -> int: |
上述算法的问题不能有效处理两种情况:
第一种情况递归为
[123]
[12]
[1]
只会递归左半,不会递归右半
第二种情况
[2222]
[222]
[22]
[2]
只会递归右半,不会递归左半
这两种情况都是O(n^2)
解决第一个问题用randomize pivot的方法
解决第二个问题用three-way partition的方法,类似于75 Sort colors将区间从两个变成3个: 小于pivot, 等于pivot,大于pivot,这样对于单一值数组,左半和右半就不会递归了
1 | def sortArray(self, nums: List[int]) -> List[int]: |
1 | public void sort(int[] arr) { |
定义: 栈里元素维持由栈底到栈顶从大到小的顺序叫递减栈。跟最小堆一样,递减栈的栈首元素最小。
反之是递增栈,不过此法因为用递减栈比较多,所以统称递减栈。通常是将下标而不是值放入到栈中,这样还可以知道元素间的距离。
求较大值 -> 递减栈
求较小值 -> 递增栈
递减栈 vs heap
实现上几乎一样,详见算法知识点目录。区别在于元素间是否需要保持顺序或者是否是stream
1 | stack = [] |
LeetCode 503 Next Greater Element II
核心思想: 原数组复制一遍,用新数组完全做一遍递减栈,最后才截取结果
1 | def nextGreaterElements(self, nums: List[int]) -> List[int]: |
时间复杂度为O(n),空间复杂度O(n)。


