递归与调用【简单版】

递归就是自己调用自己

基本递归

题目:小猴吃桃子

一只小猴买了若干个桃子。第一天他刚好吃了这些桃子的一半,又贪嘴多吃了一个;接下来的每一天它都会吃剩余的桃子的一半外加一个。第n(n≤20)天早上起来一看,只剩下 1 个桃子了。请问小猴买了几个桃子?

#include <iostream>

using namespace std;

int n, s;

void f (int t) {
	t--;
	if (t == 0) {
		return;
	}
    //现在的s是上一天剩余的桃子除2减1
	s++;  //先加一
	s *= 2;  //再乘2
    //先s++再乘2
	f(t);  //递归部分,自己调用自己 
	return;
}

int main () {
	
	cin >> n;
	
	s = 1;  //最后一天剩1个
	f(n);  //倒推,从n开始
	
	cout << s;
	
	return 0;
}

【递归】二分算法(二分查找)

顾名思义,二分就是把一个数组折半分开

贴简单二分代码:

#include <iostream>
#include <algorithm>

using namespace std;

int n, m, x;
int a[500009];

bool f (int l, int r, int t) {
    if (l > r) {
        //没有找到
        return false;
    }
    int mid = (l + r) / 2;
    if (t < a[mid]) {
        //查找的数的大小在a[mid]左边(因为有序)
        //查找范围缩小到最左边至中间 
        return f(l, mid - 1, t);
    }
    if (t > a[mid]) {
        //查找的数的大小在a[mid]右边(因为有序)
        //查找范围缩小到中间至最右边 
        return f(mid + 1, r, t);
    }
    return true;  //剩下的情况为 t == a[mid], 查找到了
}

int main () {
    
    cin >> n;
    
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    
    //先排序(做二分算法时数组必须有序)
    sort (a + 1, a + n + 1);
    
    cin >> m;  //m组查找
    
    for (int i = 1; i <= m; i++) {
        cin >> x;
        cout << (f(1, n, x)?"YES":"NO") << endl;  //是否查找到 
    }
    
    return 0;
}

来测试几个样例~

例子:

数组大小:8

数组:

index:1,2,3,4,5,6,7,8

            [5, 1,   3,   8,  11, 14, 7, 10]

排完序:

index:1,2,3,4, 5, 6, 7,  8

            [1,3,5,7,8,10,11,14]

如果查找数为3:

        mid = (1 + 8) / 2 = 4

        a[4] = 7

        3 < 7

        return f (1, 4 - 1, 3);

                   ↓

        mid = (1 + 3) / 2 = 2;

        a[2] = 3;

        return true;

如果查找数为9

        mid = (1 + 8) / 2 = 4;

        a[4] = 7;

        9 > 7

        return f (4 + 1, 8, 9);

                   ↓

        mid = (5 + 8) / 2 = 6;

        a[6] = 10;

        9 < 10;

        return (5, 6 - 1, 9);

                ↓

        mid = (5 + 5) / 2 = 5;

        a[5] = 8;

        9 > 8;

        return f (5 + 1, 5, 9);

                ↓

        l = 6; r = 5

        l > r

        return false;

的确


【递归】快速幂

从本质上看,快速幂和二分有点(一点点)像

#include <iostream>

using namespace std;

int n, m;
long long s;
//int不行,要用long long

long long pw (int num, int t) {
	if (t == 0) {
		return 1;  //不要忘了n的零次方永远是1 
	}
    if (t == 1) {
       return num;
    }
//              也是除2,与二分相似
//                    ↑↑ ↑↑   
    long long x = pw(num, t / 2);
    if (t % 2 == 0) {
//		例如3^4中4是偶数,拆成 3 ^ 2 * 3 ^ 2 
        return x * x;
    }
//	例如3^5中5是不是偶数,拆成 3 * 3 ^ 2 * 3 ^ 2 
    return num * x * x;
}

int main () {
    
    cin >> n >> m;
    
    //求n的m次方
    
    s = pw(n, m);
    
//  m次方的值增长得非常快,2^128 = 340282366920938463463374607431768211456
//  long long也存不下呢。。。
    
    cout << s;
    
    return 0;
}

取余:

计算某些n的m次方时,可能会

所以

可以在计算过程中对s取余

long long pw (long long num, long long t) {
    if (t == 0) {
        return 1;
    }
    if (t == 1) {
        return num;
    }
    long long x = pw(num, t / 2);
    if (t % 2 == 0) {
        return (x * x) % 9223372036854775807;
    }
    return (num * x * x) % 9223372036854775807;
    //9223372036854775807为long long最大值
}

当然,也有绝妙之法

题目:求结果

说明:

给你如下公式,请你求出下面公式的结果

答案太大了,请输出对2^64取模后的结果

输入格式:

第一行一个n,

后面n行,每行一对a[i], b[i];。

0 < n, a[i], b[i] ≤ 10^5

输出格式:

输出答案对2^64取模后的结果。

2^64连long long范围都超了

思路:

#include <iostream>

using namespace std;

long long n, a, b;
//使用unsigned long long
//↓↓↓  ↓↓↓
unsigned long long s;

long long pw (long long num, long long t) {
    if (t == 1) {
        return num;
    }
    long long x = pw(num, t / 2);
//  竟然不用取余!!!
    if (t % 2 == 0) {
        return x * x;
    }
    return num * x * x;
}

int main () {
    
    cin >> n;
    
    for (int i = 1; i <= n; i++) {
        cin >> a >> b;
        s += pw(a, b);
    }
    
    cout << s;
    
    return 0;
}

让他溢出就好

原理:

假设二进制

1,11111000,00001100,00000000,1000000,00110100,00011000,01011100,00010000

它已超出long long范围

会将其自动改成:

11111000,00001100,00000000,1000000,00110100,00011000,01011100,00010000

而省略掉的最前面的1,就代表2^64。


【递归】归并排序

说起来,归并排序的代码很

#include <iostream>

using namespace std;

int n;
int a[100009];
int t[100009];

void mergeSort (int l, int mid, int r) {
    int i, j, k;
    i = l; k = l;
    j = mid + 1;
    while (i <= mid && j <= r) {
        if (a[i] <= a[j]) {
            t[k++] = a[i++];
        }
        else {
            t[k++] = a[j++];
        }
    }
//  左边有剩余 ↓
    while (i <= mid) {
        t[k++] = a[i++];
    }
//  右边有剩余 ↓    
    while (j <= r) {
        t[k++] = a[j++];
    }
//  部分输出
    for (i = l; i <= r; i++) {
        a[i] = t[i];
        cout << t[i] << " ";
    }
    cout << endl;
}

void f (int l, int r) {
    if (l == r) {
        return;
    }
    int mid = (l + r) / 2;
    //分成两半 ↓
    f(l, mid);  //左
    f(mid + 1, r);  //右
    mergeSort(l, mid, r);
    return;
}

int main () {
    
    cin >> n;
    
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    
    f(1, n);
    
    for (int i = 1; i <= n; i++) {
        cout << a[i] << " ";
    }
    
    return 0;
}

细节:打架

STEP1

 STEP2

 STEP3

 STEP4

大功告成!!!

输出结果:

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值