最近找工作,准备一周左右刷完剑指,同时重点复习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++面试高频题
额 整理不完也至少整理一半叭
总之,冲鸭,为了肉和远方