蓝桥杯第二章——查找与排序

  1. 关于递归:

在函数内部调用本身这个函数叫做递归。
通常把一个大型复杂的问题转化为一个与原问题相似的规模较小的问题来求解。
注意:为了避免死循环,函数内部一定要有“出口”,即返回条件。

关于递归的简单应用:
1.求阶乘

#include 

using namespace std;

int fun(int x) {
    if(x == 1)
        return 1;
    x *= fun(x - 1);
    return x;
}

int main() {
    int x;
    while(~scanf("%d", &x)) {
        int ans = fun(x);
        printf("%d\n", ans);
    }
    return 0;
}

2.求2的n次方

#include 

using namespace std;

long long f(int n)
{
    if(n == 1)
        return 2;
        else if (n == 0)
            return 1;
    if(n % 2 == 0)
        return f(n / 2) * f(n / 2) ;
    else
    return 2 * f(n / 2) * f(n / 2) ;
}
int main() {
    long long  x;
    while(~scanf("%lld", &x)) {
        long long ans = f(x);
        printf("%lld\n", ans);
    }
    return 0;
}

关于求2的n次方,在和队友打acm院赛的时候做过一道题,题目如下

Description: 小 C 研究数学日渐憔悴,他最近对二进制数中 1 的个数十分感兴趣,他定义:cnt(x) 表示 x 的二进制下 1 的个数。
他想知道 的值 ,你能帮帮他吗? 由于值可能非常大你需要对答案模上 20190414。

Input:
第一行包含一个整数 T (1≤T≤1000) 代表测试组数,对于每一组测试:
第一行一个整数 n (0≤n≤106) ,n 的含义如上所述。

Output:对于每组测试,输出一行,表示答案。

Sample input:
2
2
100

Sample output:
5
13308891

我们这道题选了最暴力的一种做法:找规律暴力得答案(因为菜)
推出ans=n*2n-1+1;(找到规律让我膨胀了一段时间)然后直接递归求2n-1,果然T了
然后想了好久,想出来2n=2n-1*2n-1(我又膨胀了一会)
然后交了过了
代码如下:

#include 
 
using namespace std;
 
int T, n;
typedef long long LL;
const int maxn=20190414;
/*int f(int n)
{
    int a=1;
    for(int i=1;i<=n;i++)
        a=((a%maxn)*2)%maxn;
    return a;
}*/
LL f(int n)
{
    if(n == 1)
        return 2;
        else if (n == 0)
            return 1;
    if(n % 2 == 0)
        return ((f(n / 2)%maxn) * (f(n / 2)%maxn))%maxn ;
    else
    return (2 * (f(n / 2) % maxn) * (f(n / 2) % maxn)) % maxn;
}
 
int main() {
    scanf("%d", &T);
    while(T--) {
        scanf("%d", &n);
        LL a = n % maxn;
        LL b = f(n-1);
        b %= maxn;
        LL sum = (a * b) % maxn;
        printf("%lld\n", sum + 1);
    }
    return 0;
}

例题2:求数组之和

思路:就是从1一直逐个加到n,形参是数组地址,数组元素个数和初始从哪里开始加

代码:

#include 

using namespace std;

const int maxn = 1000010;
int num[maxn];
int sum(int num[], int n, int i) {
    if(i == n)
        return num[i];
    else
        return num[i] + sum(num, n, i + 1);
}


int main () {
    int t;
    scanf("%d", &t);
    for(int i = 0; i < t; i++)
        scanf("%d", &num[i]);
    int ans = sum(num, t - 1, 0);
    printf("%d", ans);
}


例题3:字符串反转
看是看懂了但是不知道怎么用c写
c里面没有charAt

例题4:斐波拉契数列(fib问题)

就是学递归的时候的基本问题,公式:fib[n]=fin[n-1]+fib[n-2]

#include 

using namespace std;

const int maxn = 1000010;
typedef long long LL;
int num[maxn];
LL fib(int n) {
    if(n == 1 || n == 2)
        return 1;
    else
        return fib(n - 1) + fib(n - 2);
}


int main () {
    int n;
    cin >> n;
    LL ans = fib(n);
    cout << ans << endl;
}

另外,错排公式也要记一下:f[n]=(n-1)*(f[n-1]+f[n-2])
上星期校赛A题:
N个题,N个答案,全部做错的答案有多少种
三个小时一直在肝这道题,一开始以为是阶乘,但是推的时候发现不太对,推到第五个的时候发现的规律。
吐槽一下学校的32位计算机,不能用long long在本地编译结果,导致用double交了四遍都有问题,后来改long long一遍过了
代码:

#include 

using namespace std;

const int maxn = 1000010;
typedef long long LL;
int num[maxn];
LL f(int n) {
    if(n == 1)
        return 0;
    if(n == 2)
        return 1;
    else
        return (n - 1) * (f(n - 1) + f(n - 2));
}


int main () {
    int n;
    cin >> n;
    LL ans = f(n);
    cout << ans << endl;
}

例题5:求最大公约数gcd

辗转相除法,当数不尽的时候结束递归得到答案

#include 

using namespace std;

const int maxn = 1000010;
typedef long long LL;
int num[maxn];
LL gcd(int m, int n) {
    if(n == 0)
        return m;
    else
        return gcd(n, m % n);
}


int main () {
    int n, m;
    cin >> m >> n;
    LL ans = gcd(m, n);
    cout << ans << endl;
}

例题6:用递归实现插入排序

插入排序就是从最后一个或者第一个开始,往数组中间插入
用递归来写拆分成每一次留下最后一个数来插入,先排之前的数
注意控制flag的范围(num[flag+1]=temp),可能会出现num[-1]的情况

#include 

using namespace std;

const int maxn = 1000010;
typedef long long LL;
int num[maxn];
void insertsort(int num[], int n) {
    if(n == 0)
        return;
    insertsort(num, n - 1);
    int temp = num[n];
    int flag = n - 1;
    while(flag > -1 && temp < num[flag]) {
        num[flag + 1] = num[flag];
        flag--;
    }
    num[flag + 1] = temp;
}


int main () {
    int t;
    scanf("%d", &t);
    for(int i = 0; i < t; i++)
        scanf("%d", &num[i]);
    insertsort(num, t - 1);
    for(int i = 0; i < t; i++)
        printf("%d ", num[i]);
}


利用递归的二分查找

二分查找前提是一个已经排好序的数组
数组开始范围(low,high),mid=(low+high)/2
如果mid大于key,就在小的那半边找,区间变为(low,mid-1)
如果mid小于key,就在大的那半边找,区间变为(mid+1,high)

代码:

#include 

using namespace std;

const int maxn = 10;
typedef long long LL;
int num[maxn];
int binsearch(int num[], int low, int high, int key) {
    if(low > high)
        return -1;
    int mid = (high + low) / 2;
    int temp = num[mid];
    if(temp > key)
        return binsearch(num, low, mid - 1, key);
    else if(temp < key)
        return binsearch(num, mid + 1, high, key);
    else
        return mid;
}


int main () {
    for(int i = 0; i < 10; i++)
        scanf("%d", &num[i]);
    int key;
    scanf("%d", &key);
    int ans = binsearch(num, 0, 9, key);
    if(ans == -1)
        cout << "Search Failed" << endl;
    else
        cout << "This number is in the " << ans + 1 << "th" << endl;
}

你可能感兴趣的:(蓝桥杯,蓝桥杯,acm,新手,查找排序,递归)