graph TD
A[原问题] --> B[子问题1]
A --> C[子问题2]
A --> D[子问题...]
B --> E[解1]
C --> F[解2]
D --> G[解...]
E --> H[合并]
F --> H
G --> H
H --> I[最终解]
style A fill:#FFE4B5
style I fill:#90EE90
voidquickSortHelper(vector<int>& nums, int left, int right){ if (left >= right) return; int pivotIndex = partition(nums, left, right); quickSortHelper(nums, left, pivotIndex - 1); quickSortHelper(nums, pivotIndex + 1, right); }
intpartition(vector<int>& nums, int left, int right){ // 随机选择pivot,避免最坏情况 int randomIndex = left + rand() % (right - left + 1); swap(nums[randomIndex], nums[right]); int pivot = nums[right]; int i = left - 1; for (int j = left; j < right; ++j) { if (nums[j] <= pivot) { swap(nums[++i], nums[j]); } } swap(nums[i + 1], nums[right]); return i + 1; }
graph TD
A[整个数组] --> B[左半部分]
A --> C[右半部分]
A --> D[跨越中点]
B --> E[递归求解]
C --> F[递归求解]
D --> G[线性扫描]
E --> H[取最大值]
F --> H
G --> H
H --> I[返回结果]
style D fill:#FFE4B5
style H fill:#90EE90
intmaxSubArrayHelper(vector<int>& nums, int left, int right){ if (left == right) return nums[left]; // 基准情况 int mid = left + (right - left) / 2; int leftMax = maxSubArrayHelper(nums, left, mid); int rightMax = maxSubArrayHelper(nums, mid + 1, right); int crossMax = maxCrossing(nums, left, mid, right); returnmax({leftMax, rightMax, crossMax}); }
intmaxCrossing(vector<int>& nums, int left, int mid, int right){ // 从中点向左扩展 int leftSum = INT_MIN, sum = 0; for (int i = mid; i >= left; --i) { sum += nums[i]; leftSum = max(leftSum, sum); } // 从中点向右扩展 int rightSum = INT_MIN; sum = 0; for (int i = mid + 1; i <= right; ++i) { sum += nums[i]; rightSum = max(rightSum, sum); } return leftSum + rightSum; }
doublemyPow(double x, longlong n){ if (n < 0) { x = 1 / x; n = -n; } double result = 1.0; while (n > 0) { if (n & 1) { // n是奇数 result *= x; } x *= x; // x = x^2 n >>= 1; // n = n / 2 } return result; }
intcountHelper(vector<int>& nums, vector<int>& temp, int left, int right){ if (left >= right) return0; int mid = left + (right - left) / 2; int count = 0; count += countHelper(nums, temp, left, mid); count += countHelper(nums, temp, mid + 1, right); count += mergeAndCount(nums, temp, left, mid, right); return count; }
intmergeAndCount(vector<int>& nums, vector<int>& temp, int left, int mid, int right){ for (int i = left; i <= right; ++i) { temp[i] = nums[i]; } int i = left, j = mid + 1, k = left, count = 0; while (i <= mid && j <= right) { if (temp[i] <= temp[j]) { nums[k++] = temp[i++]; } else { nums[k++] = temp[j++]; count += (mid - i + 1); // 关键:左边剩余都是逆序对 } } while (i <= mid) nums[k++] = temp[i++]; while (j <= right) nums[k++] = temp[j++]; return count; }
复杂度分析
时间:O(nlogn)
空间:O(n)
分治 vs 递归 vs 动态规划
三者关系
graph TD
A[递归] --> B[分治]
A --> C[动态规划]
B --> D[子问题独立]
C --> E[子问题重叠]
D --> F[直接递归求解]
E --> G[记忆化/自底向上]
style A fill:#FFE4B5
style B fill:#87CEEB
style C fill:#90EE90
对比表
特性
递归
分治
动态规划
本质
实现技术
算法思想
算法思想
子问题
-
独立
重叠
求解方式
自顶向下
自顶向下
自底向上/记忆化
典型问题
阶乘
归并排序
斐波那契
如何选择?
分治:子问题独立,无重复计算
动态规划:子问题重叠,需要记忆化
复杂度分析:主定理
主定理公式
对于递归式 T(n)=aT(n/b)+f(n),设 c=logba:
若 f(n)=O(nc−ϵ),则 T(n)=Θ(nc)
若 f(n)=Θ(nc),则 T(n)=Θ(nclogn)
若 f(n)=Ω(nc+ϵ),则 T(n)=Θ(f(n))
常见情况
递归式
算法
时间复杂度
T(n)=2T(n/2)+O(n)
归并排序
O(nlogn)
T(n)=2T(n/2)+O(1)
二分查找
O(logn)
T(n)=T(n/2)+O(n)
快速选择
O(n)
T(n)=T(n/2)+O(1)
二分幂
O(logn)
思维导图
graph TD
A[分治算法] --> B[排序问题]
A --> C[搜索问题]
A --> D[数学问题]
A --> E[统计问题]
B --> B1[归并排序]
B --> B2[快速排序]
C --> C1[二分查找]
C --> C2[第K大元素]
D --> D1[快速幂]
D --> D2[大整数乘法]
E --> E1[逆序对]
E --> E2[最大子数组]
style A fill:#FFE4B5
style B1 fill:#87CEEB
style B2 fill:#87CEEB
style C1 fill:#90EE90
style D1 fill:#DDA0DD