原理
- 将问题拆分为几个子问题,而且这些子问题和原问题相似只是量级上小一些
- 递归地解决每一个子问题,然后结合这些子问题的解决方案构造出原问题的解决方案
分治法 = 分 + 治
- 归并排序
- 快速排序
题目
1. 快速指数
计算。
https://leetcode-cn.com/problems/powx-n/
def fast_power(x, n):if n == 0:return 1elif n < 0:return 1 / fast_power(x, -n)elif n % 2:return fast_power(x * x, n // 2) * xelse:return fast_power(x * x, n // 2)
class Solution:def myPow(self, x: float, n: int) -> float:if n == 0:return 1if n < 0:return 1 / self.myPow(x, -n)if n == 1:return xans = self.myPow(x, n >> 1)ans *= ansif n & 1 == 1:# 奇数ans *= x# print(ans)return ans
2. 搜索峰值
- 数组没有重复值,但可能存在多个峰值,返回任意一个峰值的index.
- 假设num[-1] = num[n] = -∞
https://leetcode-cn.com/problems/find-peak-element/
顺序遍历一遍:nums[i - 1] < num[i] < num[i + 1], 最大时间复杂度O(n)
3. 查找中值/查找第k个元素⭐⭐⭐⭐⭐
- 排序,选择第k个,时间复杂度O(nlogn)
- O(n)的解法。参考快速排序
4. 两数组交集
- 给2个大小不一的数组,找出这两个数组的交集
- 输出中不能有重复
- set.intersection(set1, set2 … etc) intersection() 方法用于返回两个或更多集合中都包含的元素,即交集。
- 两层循环,O(n^2)
- 查找时不用in,用二分查找。(m + n) logn
- 两个数组都排序,然后维护两个指针i,j。双指针
5. 两数组交集 II
- 给2个大小不一的数组,找出这两个数组的交集
- 输出中能有重复
- Given nums1=[1, 2, 2, 1],nums2=[2, 2],return [2, 2]
- 排序,双指针
- https://www.bilibili.com/video/BV1N4411Q7D1?p=17
6. 计算逆序对
https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof/
暴力破解:两个循环,找出所有的序列对。O(n^2)
进一步优化,考虑O(nlgn)。
分治法
def merge(left, right):result = list()i, j = 0, 0inv_count = 0while i < len(left) and j < len(right):if left[i] < right[i]:result.append(left[i])i += 1elif right[j] < left[i]:result.append(right[j])j += 1inv_count += (len(left) - i)result += left[i:]result += right[j:]return result, inv_countdef countInv(array):if len(array) < 2:return array, 0middle = len(array) // 2left, inv_left = countInv(array[:middle])right, inv_right = countInv(array[middle:])merged, count = merge(left, right)count += (inv_left + inv_right)return merged, count
7. 在已排序数组中找到多余元素的索引
给定两个排好序的数组。这两个数组只有一个不同的地方:在第一个数组某个位置上多一个元素。
请找到这个元素的索引位置。
- 暴力,O(n^2)
- 遍历当前元素 + 在另外一个数组使用二分查找。 O(nlgn)
- 双指针。 O(n)
- 思考,如何O(lgn)? 二分查找。
8. 在一个一维数组中找到连续的子序列,且这个子序列的加和值最大。
https://leetcode-cn.com/problems/maximum-subarray/
- 暴力,O(n^2)
- 暴力,对加法进行优化。O(n^2),边找边加
DP。思考当前元素可能出现在连续子序列中吗?O(n)
class Solution:def maxSubArray(self, nums: List[int]) -> int:localMax, globalMax = nums[0], nums[0]for num in nums[1:]:if localMax <= 0:localMax = numelse:localMax += numglobalMax = max(globalMax, localMax)# print(globalMax)return globalMax
分治法。
分成两半,找出左边最大值,找打右边最大值。当时不意味着找到全局最大值。
9. 快速整数乘法
10. 对于多项式乘法的快速傅里叶变换
11. 矩阵乘法
12. 练习水槽

数学的方式思考,列出表达式,然后使用二分查找确定二元一次方程的根
13.奇-偶数换序问题


进一步优化,nlog(N),分治分治分治


递归有三种:分别时将递归放在头、尾和中间。头递归、尾递归和中间递归。
14.用最少步数收集所有硬币

找到高度中的最小值minimum,这个最小值意味着当横着拿的时候,拿完minimum个数之后,数组被分成了两个部分;
[L, minimum], [minimum, R]
考虑竖着拿的情况。
15.
