当前位置: 首页 > news >正文

分治算法

分治算法 (Divide and Conquer)

像“分家再合并”一样,把一个大问题拆成几个规模更小、相互独立的同类小问题。小问题各自解决后,再把它们的结果合并起来,最终得到大问题的答案。

经典问题推演:归并排序

分解:将包含 n 个元素的数组从中间劈开,分为左右两个 n/2 的子数组。
求解:递归地对左右两个子数组进行归并排序。当子数组只剩 1 个元素时,触发递归出口,天然有序。
合并:使用双指针,依次比较左右两个有序子数组的头部,将较小的元素放入辅助数组,最终合并成一个完整的有序数组。

最大子数组和问题 (Maximum Subarray Problem)

问题描述:给定一个整数数组 nums,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:输入 [-2, 1, -3, 4, -1, 2, 1, -5, 4],输出 6(因为连续子数组 [4, -1, 2, 1] 的和最大,为 6)。

为什么用分治法?

如果用暴力法,需要双重循环,时间复杂度是 \(O(n^2)\)O。而用分治法,我们可以将时间复杂度降到 \(O(nlign)\)

核心思想:跨越中点的“三种情况”
我们将数组从中间一分为二,那么“最大子数组”只可能出现在以下三种情况中:
完全在左半边:不跨越中点。
完全在右半边:不跨越中点。
跨越中点:一部分在左半边,一部分在右半边。

核心代码

#include <stdio.h>// 辅助函数:求两个数中的最大值
int max(int a, int b) { return a > b ? a : b; }// 处理跨越中点的最大子数组和
int maxCrossingSum(int arr[], int left, int mid, int right) {// 1. 从 mid 向左扫描,求包含 arr[mid] 的左半边最大和int leftSum = -999999, sum = 0;for (int i = mid; i >= left; i--) {sum += arr[i];if (sum > leftSum) leftSum = sum;}// 2. 从 mid+1 向右扫描,求包含 arr[mid+1] 的右半边最大和int rightSum = -999999; sum = 0;for (int i = mid + 1; i <= right; i++) {sum += arr[i];if (sum > rightSum) rightSum = sum;}// 3. 左右两部分相加,即为跨越中点的最大和return leftSum + rightSum;
}// 分治法主函数
int maxSubArray(int arr[], int left, int right) {// 1. 递归出口:区间只有一个元素时,最大和就是它自己if (left == right) return arr[left];// 2. 分解(Divide):找到中点int mid = left + (right - left) / 2;// 3. 求解(Conquer):分别求左半边和右半边的最大子数组和int leftMax = maxSubArray(arr, left, mid);int rightMax = maxSubArray(arr, mid + 1, right);// 4. 求解跨越中点的最大子数组和int crossMax = maxCrossingSum(arr, left, mid, right);// 5. 合并(Combine):三者取最大值return max(max(leftMax, rightMax), crossMax);
}int main() {int arr[] = {-2, 1, -3, 4, -1, 2, 1, -5, 4};int n = sizeof(arr) / sizeof(arr[0]);printf("最大子数组和为:%d\n", maxSubArray(arr, 0, n - 1));return 0;
}

示例推演

以数组 [-2, 1, -3, 4, -1] 为例(下标 0 到 4):

第 1 层分解
目标:将问题一分为二。
中点 mid = 2(元素 -3)。
原问题被拆分为:
左子问题:[-2, 1, -3] (下标 0~2)
右子问题:[4, -1] (下标 3~4)
跨越问题:必须包含 -3 和 4

第 2 层分解(处理左子问题 [-2, 1, -3])
中点 mid = 1(元素 1)。
左左:[-2] -> 递归到底,返回 -2。
左右:[1, -3] -> 继续拆分...(最终求得最大为 1)。
跨越:从 1 往左找最大和(1),从 -3 往右找最大和(-3),跨越和为 -2。
左子问题合并结果:max(-2, 1, -2) = 1。
第 2 层分解(处理右子问题 [4, -1])
中点 mid = 3(元素 4)。
右左:[4] -> 返回 4。
右右:[-1] -> 返回 -1。
跨越:4 + (-1) = 3。
右子问题合并结果:max(4, -1, 3) = 4。
第 1 层合并(处理跨越中点的问题)
目标:计算必须包含 -3 和 4 的最大和。
从 -3 向左扫描:-3,然后 -3 + 1 = -2,然后 -2 + (-2) = -4。向左最大和为 -2(只取 1 和 -3 不如只取 1,但这里必须包含 -3,所以向左最多是 1 + (-3) = -2)。注:实际代码中向左扫描包含mid,最大值为 -2。
从 4 向右扫描:4,然后 4 + (-1) = 3。向右最大和为 4。
跨越中点的最大和:-2 + 4 = 2。

最终合并
比较三种情况:左半边最大(1),右半边最大(4),跨越最大(2)。
三者取最大值:4。
(注:如果数组是 [-2, 1, -3, 4, -1, 2, 1],最终跨越中点的和会是 6,成为全局最大值)。

时间复杂度:根据主定理,递推公式为
\(T(n)=2T(n/2)+O(n)\) ,时间复杂度为 \(O(nlogn)\)
核心难点:分治法的难点永远在合并(Combine)阶段。对于最大子数组问题,跨越中点的计算不能简单相加,必须分别向左、向右扫描求最大和。

http://www.jsqmd.com/news/1175887/

相关文章:

  • 西安成人学历机构避坑指南:这6类承诺别信 - 最新政策解读
  • 为什么选择ReactPrimer?这款组件原型工具如何提升你的开发效率
  • M87生成艺术作品赏析:24个惊艳案例带你领略AI美学新高度
  • AI+城市配送网络:多级仓储+动态路由+需求预测
  • HNU-2026操作系统-学习感悟与总结
  • 2026年7月最新沈阳卡地亚官方售后热线及客户服务网点地址 - 卡地亚服务中心
  • Saucer线程安全机制与协程支持:编写高效异步桌面应用的最佳实践
  • Word 2019 自定义样式集成自动目录:3步解决非标准标题识别难题
  • 北京恒略房产合同纠纷律师咨询电话16601232889同微信 - 北京普法者
  • FeedFlow深度评测:为什么这款开源RSS阅读器值得取代你的新闻App?
  • 为什么选择FeedFlow?5个让你告别信息过载的理由
  • 全球 7.5 万台防火墙“底裤被扒”,45张显卡暴力狂飙背后的黑客流水线
  • 仅剩最后200份|《AI Agent自动数据分析黄金配置包》:含17个预训练Agent微调权重、5类行业Schema本体库、实时SQL纠错引擎v2.3(限本周免费领取)
  • LangGraph快速入门-01概述
  • Linux --- D-Bus 系统总线
  • 自考本科含金量高吗:从认可度说清楚 - 最新政策解读
  • CANN/ascend-transformer-boost ATB加速库对外头文件和库文件说明
  • Qt 6.7 MSVC 编译器配置:3步修复 ‘Cannot run compiler cl‘ 环境变量问题
  • 2026年GEO源头厂商选型避坑指南:杭州爱搜索实战评测与护城河解析 - 品牌报告
  • Saucer多后端支持深度测评:Windows WebView2 vs Linux WebKitGtk vs macOS WKWebView
  • 2025年【江苏“信息与未来”编程思维】真题及题解(T4:成语接龙)
  • KeeAnywhere快速入门:5分钟完成KeePass云同步插件安装与配置
  • Django REST Framework API Key性能优化:提升密钥验证速度的实用方法
  • 钢铁厂0.002mm精度测量:3项技术突破生产瓶颈
  • 海口钻石上门回收全解析,高价值钻戒居家变现避坑实测 - 每日生活报
  • 广州中检认证收钻铺 TOP5 红榜,2026 实测杜绝无证书随意折价 - 每日生活报
  • 零基础入门GeoNet:从环境搭建到数据准备的完整指南
  • 西安高校授权教学点有哪些:认准正规合作 - 最新政策解读
  • MaterialValues布局资源:结构、间距和边距的标准化实现
  • 厦门百达翡丽回收价格查询和靠谱平台实测排行(2026年7月最新数据) - 天价名表回收平台