c++面试准备——递归练习1

最近找工作,准备一周左右刷完剑指,同时重点复习C++基础、操作系统、算法和计网,用博客记录方便复习,希望顺利拿到OFFER;

以及,有段时间没写过题目了,感觉有些生疏…害, 加油吧

翻转单词

// 递归实现

//用一个新的字符串来保存答案
string s; //需要翻转的单词
string getans(int n) {
    string ans = "";
    if(n == s.length()) return "";
    ans = getans(n + 1);
    ans.push_back(s[n]);
    return ans;
}

//不用额外空间,直接输出
void getans1(int n) {
    if(n == s.length()) return;
    getans1(n + 1);
    cout << s[n];
}

斐波那契数列

F(n) = F(n - 1) + F(n - 2), 给出n求F(n);


// 斐波那契数列
int Fibonacci(int n) {
    return n == 1 || n == 0 ? n : Fibonacci(n - 1) + Fibonacci(n - 2);
}

代码量低,但效率不高,当n较大时,执行速度很慢,需要进行优化;

// 采用vector记录已经计算过的值,去除重复计算
// vector<int>vec(30, -1)
int Fibonacci(int n, vector<int>vec) {
    if(vec[n] != -1) return vec[n];
    vec[n] =  n == 1 || n == 0 ? n : Fibonacci(n - 1, vec) + Fibonacci(n - 2, vec);
    return vec[n];
}

比之前好一些,但还不够,继续优化,考虑不用递归解决;

// 循环
int Fibonacci(int n) {
    if(n == 0 || n ==1) return n;
    int F0, F1, Fn;  //只需要用三个记录向后走即可求得Fn;
    F0 = 0, F1 = 1;
    for(int i = 2; i <= n; i ++)  {
        Fn = F0 + F1;
        F0 = F1;
        F1 = Fn;
    }
    return Fn;
}

俺觉得OK啦, 下一题

青蛙跳台阶

青蛙每次可以跳一步或两步,求跳n步的方案数;

斐波那契的变题,用F(i)表示跳i步的方案数,关键在于分析出F(i)的表达式;

考虑第一步:
假设青蛙跳了一步,则此后跳到n步的方案数为F(n - 1);
假设青蛙跳了两步,则此后跳到n步的方案数为F(n - 2);
由于只存在这两种可能,不难得出F(n) = F(n - 1) + F(n - 2);
注意F(1) = 1, F(2) = 2;
即变成斐波那契求第n项的值;

汉诺塔

有三个柱子ABC,只有A上有盘子。要求把A上的n个盘子全部移到C。(任意时刻小盘子只能放在大盘子之上)

采取的策略应该是,当A上只有一个盘子时,直接将其移到C;当A上有n(n>1)个盘子时,将A上的n-1个盘子移到B,剩下的一个盘子移到C,最后将B上的n-1个盘子移到C;

// 递归实现汉诺塔
void hanota(int n, vector<int>&a, vector<int>&b, vector<int>&c) {
    if(n == 0) return;
    if(n == 1) {
        c.push_back(a.back());
        a.pop_back();
    } 
    hanota(n - 1, a, c, b) // 借助c将a上的n-1个盘子移到b
    c.push_back(a.back());
    a.pop_back();      // 剩下的一个盘子移到c
    hanota(n - 1, b, a, c) //借助a将b上的n-1个盘子移到c
}

电话号码组合

输入一个只包含数字2-9的字符串,要求输入所有可表示的字母组合;
每个数字有自己对应的字母:
在这里插入图片描述

string s; //输入的字符
vector<string>v0;  //用来保存答案
vector<string>v1 = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; 
void getans(int now, string ans) {
    if(now == s.length()) {  //每个数字都已经选择过字母,保存答案
        v0.push_back(ans); 
        return;
    }
    int l = s[now] - '0';
    for(int i = 0; i < v1[l].size(); i ++) {
        ans.push_back(v1[l][i]); //在当前数字可代表的所有字母中选择一个
        getans(now + 1, ans);  //选择完毕,进入下一个数字的字母选择
        ans.pop_back(v1[l][i]); //恢复
        //若当前数字还有字母可选,进入下次循环,为当前数字重新选择新的字母;
    }
}
int main() {
    cin >> s;
    getans(0, "");
    return 0;
}

合并两个有序链表

合并两个升序排列的链表A, B,要求合并后依然为升序;

采取的策略是:用指针a, b同时遍历A, B,每次比较a, b结点值,选出较小的一个,然后继续合并A, B剩余的其他节点;

struct pnode {
    int val;
    pnode * next;
};
pnode * merge(pnode * a, pnode * b) {
    if(a == NULL) return b; //a走完时直接与B剩下的结点合并
    if(b == NULL) return a; //同理
    if(a -> val < b -> val) {
        a -> next = merge(a -> next, b);
        return a;
    }
    else {
        b -> next = merge(a, b -> next);
        return b;
    }
}

——
——
——
明天刷剑指11-20题 希望今晚可以整理完C++面试高频题
额 整理不完也至少整理一半叭

总之,冲鸭,为了肉和远方

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值