递归
递归,就是在一个函数中调用本身,可以将一个大问题不断拆解到最基础的情况。但是需要注意,对于递归的方法,需要明确递归出口,即“什么情况下递归结束”。否则递归函数会一直调用其本身,直到内存溢出。
递归问题有一道十分经典的例题,就是大名鼎鼎的汉诺塔问题:
分析: 我们从递归的视角去分析,我们想要的第一步就是把1~n-1的盘子从A移到B上,这样就可以顺利把最大的盘子移到C上,最后把1~n-1移到C上即可(这就是盘子数量为n-1的汉诺塔问题)。 如此分析,可以得出递归参数: 4个参数(盘子数量x,起点柱子s,终点柱子e,媒介柱子h)
下面是代码示例:
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void move(int x, vector<int>& s, vector<int>& e, vector<int>& h, char s1, char e1, char h1){
if(x == 1){
int d = s.back();
s.pop_back();
e.push_back(d);
cout << d << ' ' << s1 << "-->" << e1 << endl;
return;
}
move(x-1, s, h, e, s1, h1, e1);
int d = s.back();
s.pop_back();
e.push_back(d);
cout << d << ' ' << s1 << "-->" << e1 << endl;
move(x-1, h, e, s, h1, e1, s1);
}
void hanota(vector<int>& A, vector<int>& B, vector<int>& C) {
int n = A.size();
move(n, A, C, B, 'a', 'c', 'b');//把n个盘子从A移到C,经由B的帮助
}
int main(){
vector<int> a;
vector<int> b;
vector<int> c;
int n, x;
cin >> n;
for(int i = 0; i < n; ++i){
cin >> x;
a.push_back(x);
}
hanota(a, b, c);
for(int i = 0; i < n; ++i){
cout << c[i] << ' ';
}
cout << endl;
return 0;
}
分治
分治,字面上的解释是“分而治之”,就是把一个复杂的问题分成两个或更多的相同或不相同的子问题,子问题相互独立,直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
我们来看一道例题~
分析: 这道题可以用暴力、分治、动态规划来做,我们这里只讲解分治的算法,大家有兴趣可以去思考一下动态规划的做法。 我们把这个数组从中间分开,那么会有一部分子数组在左侧,会有一部分子数组在右侧,还有一部分子数组两侧各有一些元素。我们分开算出这三种情况的答案,然后取max即可。
对于左侧和右侧的情况,我们发现其实就是求l到mid以及mid到r的最大子数组和,那么我们可以考虑递归求解; 对于横跨中间的子数组,我们考虑从mid先向左延伸所能取到的最大值,再考虑向右延伸所能取到的最大值,两者相加即可。
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
int maxxmid(vector<int>& nums, int l, int mid, int r){
//包括mid,向左延伸最大值
int lmax = INT_MIN;
int sum = 0;
for(int i = mid; i >= l; --i){
sum += nums[i];
lmax = max(lmax, sum);
}
//不包括mid,向右延伸最大值
int rmax = INT_MIN;
sum = 0;
for(int i = mid+1; i <= r; ++i){
sum += nums[i];
rmax = max(rmax, sum);
}
return lmax+rmax;
}
int maxxans(vector<int>& nums, int l, int r){//求nums[l]~nums[r]的最大子数组和
if(l == r){
return nums[l];
}
int mid = (l+r) / 2;
//l ~ mid
int a1 = maxxans(nums, l, mid);
//mid+1 ~ r
int a2 = maxxans(nums, mid+1, r);
//横跨mid
int a3 = maxxmid(nums, l, mid, r);
return max(max(a1, a2), a3);
}
int maxSubArray(vector<int>& nums) {
int ans = INT_MIN;
int n = nums.size();
ans = maxxans(nums, 0, n-1);
}
int main(){
int n, x;
vector<int> nums;
cin >> n;
for(int i = 0; i < n; ++i){
cin >> x;
nums.push_back(x);
}
int ans = maxSubArray(nums);
cout << ans << endl;
return 0;
}
这种做法时间还是有点长,感兴趣的可以去试试动态规划,时间复杂度只有O(n)。