递归与分治

1.递归

    递归思想是把问题转化为规模缩小了的同类问题的子问题,然后递归调用函数(或过程)来表示问题的解;一个过程(或函数)直接或间接调用自己本身,这种过程(或函数)叫递归过程(或函数)。

    1.特点:

   (1)递归就是在过程或函数里调用自身。
   (2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
   (3)递归算法解题通常显得很简洁,但递归算法解题的运行效率较低。所以一般不提倡用递归算法设计程序。

    2.举例:

    斐波拉契数列问题:构造斐波拉契数列就用了递归思想

class Solution {
public:
	int Fibonacci(int n) {
		int* A = new int[n+1];
		A[0] = 0;
		A[1] = 1;
		if (n == 0) {
			return 0;
		}
		if (n == 1) {
			return 1;
		}
		for (int i = 2; i <=n; i++) {
			A[i] = A[i - 1] + A[i - 2];
		}
		return A[n];
	}
};

    同样斐波拉契数列也可以抽象成具体的问题:一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?对于这个问题,青蛙跳上n阶台阶和它跳上n-1阶与n-2阶之和相同,所以这就是求斐波拉契数列的第n项

2.分治

    分治思想是将待解决复杂的问题能够简化为几个若干个小规模相同的问题,达到易于解决的程度。

    1.特点:

    (1)将原问题分解为n个规模较小的子问题,各子问题间独立存在,并且与原问题形式相同

    (2)递归的解决各个子问题

    (3)将各个子问题的解合并得到原问题的解

    2.举例:

    分治法思想典型的例子就是大数相乘,通过把一个大数分解成长度为2的小段再分别求解,最后合并解。

#include
#include 
#include 
#include 
using namespace std;

//字符串转化为int型
int str_to_int(string str) {
	int i;
	stringstream stream(str);
	stream >> i;
	return i;
}

//int转换为字符串
string int_to_str(int i) {
	string str;
	stringstream stream;
	stream << i;
	stream >> str;
	return str;
}

//删除大数前面多余的零
void removeprezero(string &str) {
	if (str.length() == 1) return;
	int k = 0;
	for (int i = 0; i < str.length(); i++) {
		if (str[i] == '0') {
			k++;
		}
		else {
			break;
		}
	}
	if (k == str.length()) {
		str = '0';
	}
	else {
		str = str.substr(k);
	}
}

//大数求和
string add(string x, string y) {
	string result = "";
	removeprezero(x);
	removeprezero(y);
	reverse(x.begin(), x.end());
	reverse(y.begin(), y.end());
	//j是前一位的进位,k是本位的和
	for (int i = 0, j = 0; j || i < max(y.length(), x.length()); i++) {
		int k = j;
		if (i < x.length()) k += (x[i] - '0');
		if (i < y.length()) k += (y[i] - '0');
		result.insert(0, int_to_str(k % 10));
		j = k / 10;
	}
	return result;
}

//为了统一两个数的长度,计算前在大数前加零
void addprezero(string &str, int zero_num) {

	for (int i = 0; i < zero_num; i++) {
		str.insert(0, "0");
	}
}

//大数不能直接×10,通过移位加零
string addlastzero(string str, int zero_num) {
	string s = str;
	for (int i = 0; i < zero_num; i++) {
		s += "0";
	}
	return s;
}

string  multiply(string &x, string &y) {

	bool flag_x = false; //正
	bool flag_y = false;
	bool flag;
	if (x[0] == '-') {
		flag_x = true;
		x = x.substr(1);
	}
	if (y[0] == '-') {
		flag_y = true;
		y = y.substr(1);
	}
	if ((flag_x && flag_y) || (!flag_x && !flag_y)) {
		flag = false;
	}
	else {
		flag = true;
	}

	/**
	* 预处理,将x和y处理成相同位数的两个数
	* x和y的长度必须是2的指数倍,这样才能递归分治计算
	* 所以需要将x和y添加前置0,将长度处理为可行的最小的长度
	*
	* 处理过后x和y的长度将统一
	*/
	int init_len = 2;
	if (x.length() >= 1 || y.length() >= 1) {
		if (x.length() >= y.length()) {
			while (init_len < x.length()) {
				init_len *= 2;
			}
			if (x.length() != init_len) {
				addprezero(x, init_len - x.length());
			}
			addprezero(y, init_len - y.length());
		}
	}
	else {
		while (init_len < y.length()) {
			init_len *= 2;
		}
		addprezero(x, init_len - x.length());
		if (y.length() != init_len) {
			addprezero(y, init_len - y.length());
		}
	}
	int n = x.length();
	string result;
	string a1, a2, b1, b2;
	if (n > 1) {
		a2 = x.substr(0, n / 2);
		a1 = x.substr(n / 2, n);
		b2 = y.substr(0, n / 2);
		b1 = y.substr(n / 2, n);
	}
	if (n == 2) { //长度为2,结束递归
		int x2 = str_to_int(a2);
		int x1 = str_to_int(a1);
		int y2 = str_to_int(b2);
		int y1 = str_to_int(b1);
		int z = (x2 * 10 + x1) * (y2 * 10 + y1);
		result = int_to_str(z);
	}
	/**
	*	这里就是 a*b = (a2 * 10^n/2 + a1) * (b2 * 10^n/2 + b1)
	*	             = (a2 * b2 * 10^n) + (a1 * b1) + ((a1 * b2) + (a2 * b1)) * 10^n/2
	**/
	else {
		string c1 = addlastzero(multiply(a2, b2), n);
		string c2 = multiply(a1, b1);
		string c3 = addlastzero(add(multiply(a1, b2), multiply(a2, b1)), n / 2);
		result = add(add(c1, c2),c3);
	}
	if (flag) {
		result.insert(0, "-");
	}
	return result;
}
int main() {
	string s1 = "-1434324233";
	string s2 = "3434324324";
	string result = multiply(s1, s2);
	cout << result << endl;
	return 0;
}

 

你可能感兴趣的:(算法,Recursive,divide,and,conquer)