<think>我们正在讨论C++中的分治算法示例题目和代码实现。根据引用内容,我们可以参考LeetCode上的几个经典分治问题。以下是三个常见的例题及其C++实现:1.**Leetcode50:Pow(x,n)**-实现幂函数2.**Leetcode169:多数元素**-寻找数组中出现次数超过一半的元素3.**Leetcode53:最大子序和**-求连续子数组的最大和下面分别给出这三个问题的分治解法代码实现。###1.Leetcode50:Pow(x,n)题目要求实现计算$x$的$n$次幂的函数,即$pow(x,n)$。使用分治法可以降低时间复杂度到$O(\logn)$。**分治思路**:-将$n$分解为两半,计算$pow(x,n/2)$,然后根据$n$的奇偶性合并结果。-注意处理$n$为负数的情况。```cppclassSolution{public:doublemyPow(doublex,intn){longlongN=n;//防止n为负数时取相反数溢出if(N<0){x=1/x;N=-N;}returnfastPow(x,N);}doublefastPow(doublex,longlongn){if(n==0){return1.0;}doublehalf=fastPow(x,n/2);if(n%2==0){returnhalf*half;}else{returnhalf*half*x;}}};```###2.Leetcode169:多数元素题目要求找出数组中出现的次数大于$\lfloorn/2\rfloor$的元素。**分治思路**:-将数组分成左右两部分,分别求出左半部分的众数和右半部分的众数。-如果左右两部分的众数相同,则直接返回。-如果不同,则在整个数组中统计这两个数出现的次数,返回出现次数多的那个。```cppclassSolution{public:intmajorityElement(vector<int>&nums){returnmajorityElementRec(nums,0,nums.size()-1);}intmajorityElementRec(vector<int>&nums,intleft,intright){//递归终止条件:当子数组只有一个元素时,该元素就是众数if(left==right){returnnums[left];}//分治:将数组分成左右两部分intmid=left+(right-left)/2;intleftMajority=majorityElementRec(nums,left,mid);intrightMajority=majorityElementRec(nums,mid+1,right);//如果左右两部分的众数相同,则直接返回if(leftMajority==rightMajority){returnleftMajority;}//否则,统计左右众数在整个子数组中的出现次数intleftCount=countInRange(nums,left,right,leftMajority);intrightCount=countInRange(nums,left,right,rightMajority);returnleftCount>rightCount?leftMajority:rightMajority;}intcountInRange(vector<int>&nums,intleft,intright,inttarget){intcount=0;for(inti=left;i<=right;i++){if(nums[i]==target){count++;}}returncount;}};```###3.Leetcode53:最大子序和题目要求计算一个整数数组中的连续子数组的最大和。**分治思路**:-将数组分成左右两部分,最大子序和可能出现在左半部分、右半部分或跨越左右两部分。-分别递归求出左半部分和右半部分的最大子序和。-再计算跨越中点的最大子序和(从中点向左扩展和向右扩展,取最大和)。-最后取三者中的最大值。```cppclassSolution{public:intmaxSubArray(vector<int>&nums){returnmaxSubArrayHelper(nums,0,nums.size()-1);}intmaxSubArrayHelper(vector<int>&nums,intleft,intright){if(left==right){returnnums[left];}intmid=left+(right-left)/2;//分别求左右子数组的最大子序和intleftSum=maxSubArrayHelper(nums,left,mid);intrightSum=maxSubArrayHelper(nums,mid+1,right);//求跨越中点的最大子序和intcrossSum=crossSubArray(nums,left,right,mid);//返回三者中的最大值returnmax(max(leftSum,rightSum),crossSum);}intcrossSubArray(vector<int>&nums,intleft,intright,intmid){//从中点向左扩展,求最大和intleftSum=INT_MIN;intsum=0;for(inti=mid;i>=left;i--){sum+=nums[i];leftSum=max(leftSum,sum);}//从中点向右扩展,求最大和intrightSum=INT_MIN;sum=0;for(inti=mid+1;i<=right;i++){sum+=nums[i];rightSum=max(rightSum,sum);}//合并左右两边的和returnleftSum+rightSum;}};```###总结以上三个例题展示了分治算法的典型应用:将问题分解为规模更小的子问题,递归求解,然后合并结果。分治法通常能降低问题的时间复杂度(如从$O(n)$到$O(\logn)$),但需要注意递归的终止条件以及合并结果的逻辑。§§相关问题§§1.分治算法和动态规划有什么区别?2.除了以上例题,还有哪些经典问题可以用分治算法解决?3.分治算法的时间复杂度分析通常使用什么方法?</think>### C++ 分治算法示例题目及代码实现
分治算法通过**分解→解决→合并**三步解决复杂问题,以下是三个经典例题的C++实现:
---
#### 1. **Leetcode 50: Pow(x, n)** [^1]
**问题**:实现计算 $x^n$ 的函数。
**分治思路**:
- 分解:$x^n = x^{n/2} \times x^{n/2}$(若 $n$ 为偶数)
- 合并:根据 $n$ 的奇偶性调整结果
```cpp
class Solution {
public:
double myPow(double x, int n) {
long long N = n; // 防止n为负数时溢出
if (N < 0) {
x = 1 / x;
N = -N;
}
return fastPow(x, N);
}
double fastPow(double x, long long n) {
if (n == 0) return 1.0;
double half = fastPow(x, n / 2);
return (n % 2 == 0) ? half * half : half * half * x;
}
};
```
**时间复杂度**:$O(\log n)$
---
#### 2. **Leetcode 169: 多数元素** [^1]
**问题**:找出数组中出现次数超过 $\lfloor n/2 \rfloor$ 的元素。
**分治思路**:
- 分解:将数组分为左右两半
- 解决:递归求左右子数组的众数
- 合并:统计两个众数在整个数组的频率,取更高者
```cpp
class Solution {
public:
int majorityElement(vector<int>& nums) {
return divide(nums, 0, nums.size()-1);
}
int divide(vector<int>& nums, int l, int r) {
if (l == r) return nums[l];
int mid = l + (r - l) / 2;
int leftMajor = divide(nums, l, mid);
int rightMajor = divide(nums, mid+1, r);
// 合并:统计左右众数的全局频率
if (leftMajor == rightMajor) return leftMajor;
int leftCount = count(nums, l, r, leftMajor);
int rightCount = count(nums, l, r, rightMajor);
return leftCount > rightCount ? leftMajor : rightMajor;
}
int count(vector<int>& nums, int l, int r, int target) {
int cnt = 0;
for (int i = l; i <= r; ++i) {
if (nums[i] == target) cnt++;
}
return cnt;
}
};
```
**时间复杂度**:$O(n \log n)$
---
#### 3. **Leetcode 53: 最大子序和** [^1]
**问题**:计算连续子数组的最大和。
**分治思路**:
- 分解:将数组分为左右两半
- 解决:递归求左半、右半的最大和
- 合并:计算跨越中点的最大和(关键步骤)
```cpp
class Solution {
public:
int maxSubArray(vector<int>& nums) {
return maxSub(nums, 0, nums.size()-1);
}
int maxSub(vector<int>& nums, int l, int r) {
if (l == r) return nums[l];
int mid = l + (r - l) / 2;
int leftSum = maxSub(nums, l, mid); // 左半最大和
int rightSum = maxSub(nums, mid+1, r); // 右半最大和
int crossSum = maxCrossing(nums, l, r); // 跨越中点的最大和
return max({leftSum, rightSum, crossSum});
}
int maxCrossing(vector<int>& nums, int l, int r) {
int mid = l + (r - l) / 2;
// 向左扩展的最大和
int leftSum = INT_MIN, sum = 0;
for (int i = mid; i >= l; --i) {
sum += nums[i];
leftSum = max(leftSum, sum);
}
// 向右扩展的最大和
int rightSum = INT_MIN;
sum = 0;
for (int i = mid+1; i <= r; ++i) {
sum += nums[i];
rightSum = max(rightSum, sum);
}
return leftSum + rightSum;
}
};
```
**时间复杂度**:$O(n \log n)$
---
### 分治算法核心要点总结
1. **适用场景**:问题可分解为**相互独立**的子问题(如数组分块、树形结构)
2. **关键步骤**:
- **分解**:将原问题划分为规模相同的子问题
- **解决**:递归求解子问题(递归终止条件需明确定义)
- **合并**:将子问题的解组合成原问题的解
3. **效率优势**:通过降低问题规模(如二分)将 $O(n)$ 优化至 $O(\log n)$
> 引用说明:示例题目均来自LeetCode经典分治问题[^1],代码实现采用标准分治模板[^2]。