算法:递归和查找

目录

典型例题

斐波那契数列

 递归求最大公约数

汉诺塔

二分查找法的递归形式

小白上楼梯问题

在有空字符串的有序字符串数组中查找(二分查找)

找最长连续递增子序列(双指针)


 

*递归的思想

(1)找重复  例如我要写n的阶乘,n的阶乘可以表示n*(n-1)的阶乘,求n-1的阶乘是原问题的重复(规模更小)--子问题

i)找到一种划分方式  ii)找到一种递推公式
(2)找变化  变化的量应该作为边界

(3)找边界  出口   一般我们用if条件来规定出口

我们可以将递归分解为:(1)直接量+小规模问题

                                      (2)多个小规模问题

典型例题

斐波那契数列

啥叫斐波那契数列呢?

如1,1,2,3,5,8,13,21.....就是除了第一个和第二个数之外,其他数等于前两个数之和

#include<iostream>
#include<string>
using namespace std;
//斐波那契数列的指定的前n项
int Fib(int n)
{
	if (n == 1 || n == 2)
	{
		return 1;
	}
	return Fib(n - 2) + Fib(n - 1);
}
int main()
{
	int n;
	cin >> n;
	int N = Fib(n);
	cout << N;
	return 0;
}

 递归求最大公约数

思路:我们先让n%m,如果能余数为0,那么m就是最大公约数,如果余数不是0,那我们把余数叫做k,那就m%k,如果能余数是0,那k就是最大公约数,不是0,那就让k%(m与k的余数),一直这样操作,总会找到一个数,哪怕是1 

#include<iostream>
#include<string>
using namespace std;
int MAx(int n, int m)
{
	if (n % m ==0)
	{
		return m;
	}
	else {
		MAx(m, n % m);
	}
}
int main()
{
	//n,m的最大公约数
	int n, m;
	cin >> n >> m;
	int number = MAx(n, m);
	cout << number<<endl;
	return 0;
}

汉诺塔

相传在古印度圣庙中,有一种被称为汉诺塔(Hanoi)的游戏。该游戏是在一块铜板装置上,有三根杆(编号A、B、C),在A杆自下而上、由大到小按顺序放置若干个金盘(如下图)。游戏的目标:把A杆上的金盘全部移到C杆上,并仍保持原有顺序叠好。操作规则:每次只能移动一个盘子,并且在移动过程中三根杆上都始终保持大盘在下,小盘在上,操作过程中盘子可以置于A、B、C任一杆上

我们的思路就是我们先把上面N-1个盘子,放到中间的withPole(我们也叫做help),就是下面这个图

然后我们把最下面那个盘子放到toPole上

最后把withPole上的盘子放到toPole上

我们用代码写这个过程的时候,我注意,我们不是直接挪动,而是借助另一个help来移动 

我们先把上面N-1个盘子,放到中间的withPole(我们也叫做help),是借助了toPole移过去的

最后把withPole上的盘子放到toPole上是借助from移过去的

所以下面用代码实现的时候要加一个help辅助

#include<iostream>
#include<string>
using namespace std;
void HanoiTower(int N, string from, string to, string help)
{
	if (N == 1)
	{
		cout << " move " << N << " from " << from << " to " << to << endl;
	}
	else {
		HanoiTower(N - 1, from, help, to);
		cout<< " move " << N << " from " << from << " to " << to << endl;
		HanoiTower(N - 1, help, to, from);
	}
}
int main()
{
	HanoiTower(3, "A", "C", "B");
	return 0;
}

二分查找法的递归形式

#include<iostream>
#include<string>
using namespace std;
int binarySearch(int arr[], int begin, int end, int key)
{
	if (begin > end)
		return -1;
	int mid = (begin + end) / 2;
	int midVal = arr[mid];
	if (midVal < key)
	{
		return binarySearch(arr, mid + 1, end, key);
	}
	else if (midVal > key)
	{
		return binarySearch(arr, begin, mid - 1, key);
	}
	else {
		return mid;
	}
}
int main()
{
	int arr[] = { 0,1,2,3,4,5,6,7,8,9 };
	int index = binarySearch(arr, 0, 9, 5);
	cout << index << endl;
	return 0;
}

小白上楼梯问题

小白正在上楼梯,楼梯有n阶台阶,小白一次一次可以上1阶,2阶或3阶,实现一个方法,计算小白有多少种走完楼梯的方式。

思路:我们可以先倒着想这个问题,我们可以从n-1阶直接走到n阶,也可以从n-2阶走到n阶,也可以从n-3阶走到n阶,这样想的前提是小白已经到达了n-1或n-2或者n-3阶

n-1阶到n阶直接迈一步,1种走法

n-2阶到n阶可以直接上n阶,也可以先走到n-1阶再到n阶,2种走法,我们需要注意的是,后面的走法已经包含到了n-1到n阶里面了

n-3阶到n阶可以直接上n阶,也可以先到n-2再到n阶,可以先到n-1再到n阶,也可以一步一步来,但是后面的几种情况包含到了n-1阶到n阶和n-2阶到n阶的情况了

到n阶的问题就转化到小白到n-1阶的方式与n-2阶的方式与n-3的方式之和

,即f(n) = f(n-1)+f(n-2)+f(n-3)

#include<iostream>
using namespace std;
int Func(int n)
{
	if (n == 0)return 0;
	if (n == 1)return 1;
	if (n == 2)return 2;
	return Func(n - 1) + Func(n - 2) + Func(n - 3);
}
int main()
{
	int n;
	cin >> n;
	cout << Func(n) << endl;
	return 0;
}

在有空字符串的有序字符串数组中查找(二分查找)

假如说我给了一个字符串数组{ "a","","ac","","ad","b","","ba" },里面的空字串是随机分布的,我要找到里面"b"的下标,怎么办呢?我们用二分,找到中间的元素,如果说中间元素是空字符串,那我们就+1,如果+1还是空字符串我们还+1(上述也可以把+1换成-1,就是找到字符串能比较就行)

#include<iostream>
#include<stdlib.h>
#include<stdbool.h>
#include<string>
using namespace std;
int Fuc(string* a, int begin, int end, string key)
{
	while (begin <= end)
	{
		int mid = (begin + end) / 2;
		while (a[mid] == "")
		{
			mid += 1;
		}
		if (a[mid].compare(key) == -1)
		{
			begin = mid + 1;
		}
		else if (a[mid].compare(key) == 1)
		{
			end = mid - 1;
		}
		else {
			return mid;
		}
	}
	return -1;
}
int main()
{
	string arr[] = { "a","","ac","","ad","b","","ba" };
	int n = sizeof(arr) / sizeof(string);
	string key = "b";
	int index = Fuc(arr, 0, n - 1, key);
	cout << arr[index];
	return 0;
}

找最长连续递增子序列(双指针)

题意:假如说我给了一个数组{1,9,2,5,7,3,4,6,8,0},最大子序列是{3,4,6,8},写出程序找出来最大子序列

我们用双指针的快慢指针,慢指针先指向0,快指针先指向1,我们一开始设置一个index变量存放有序子序列的头索引,然后如果快指针比慢指针对应的值大,那就让快指针和慢指针都+1,count+1,如果小了,我们就让快指针等于慢指针,慢指针+1寻找下一个有序子序列

#include<iostream>
#include<stdlib.h>
#include<stdbool.h>
#include<string>
#include<vector>
using namespace std;
int main()
{
	int a[] = { 1, 9, 2, 5, 7, 3, 4, 6, 8, 0 };
	int slow = 0;
	int fast = slow + 1;
	int n = sizeof(a) / sizeof(int);
	vector<int>count1;
	vector<int>index1;
	while(fast<n)
	{ 
		int count = 1;
		int index = slow;
		while(a[fast] > a[slow])
		{
			fast += 1;
			slow += 1;
			count += 1;
		}
		slow = fast;
		fast += 1;
		count1.push_back(count);
		index1.push_back(index);
	}

	int maxi = count1[0];
	int num = 0;
	for (int i = 0; i < count1.size(); i++)
	{
		if (count1[i] > maxi)
		{
			maxi = count1[i];
			num = i;
		}
	}
	for (int i = index1[num]; i <index1[num]+maxi ; i++)
	{
		cout << a[i] << " ";
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值