面试题06. 从尾到头打印链表
题目描述:
输入一个链表的头节点,从尾到头反过来返回每个节点的值(用数组返回)。
输入:head = [1,3,2]
输出:[2,3,1]
限制:
0 <= 链表长度 <= 10000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/cong-wei-dao-tou-da-yin-lian-biao-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
采用一个栈, 实现逆序
代码
vector<int> reversePrint(ListNode* head) {
auto ptr = head;
vector<int> lst;
stack<int> sta;
// 将链表内容,输入栈中
while( ptr != NULL){
sta.push(ptr->val);
ptr = ptr->next;
}
// 逆序输出到向量中
while(!(sta.empty())){
lst.push_back(sta.top());
sta.pop();
}
return lst;
}
面试题07. 重建二叉树
题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/
9 20
/
15 7
思路
对于二叉树的问题,常常会采用递归,应为二叉树本身就是递归定义。而递归和二叉树对于初学者来说确实很有难度,这道题我查看题解很长时间,才略懂。
图片来源:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/er-cha-shu-de-qian-xu-bian-li-fen-zhi-si-xiang-by-/
特点:
- 根据前序遍历可以,前序遍历的第一个元素为一个根结点
- 根据中序遍历序列中,中间的根结点可以将整个序列划分成左子树序列和右子树序列
- 根据中序遍历中左、右子树序列的数目,可以推断出在前序遍历序列中的左、右子树的边界。如图所示。
代码
// 注意 迭代器的区间是左闭右开
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
return recurisonBuild(preorder.begin(), preorder.end(), inorder.begin(), inorder.end());
}
TreeNode* recurisonBuild(vector<int>::iterator preBegin, vector<int>::iterator preEnd,
vector<int>::iterator inBegin, vector<int>::iterator inEnd)
{
if(inBegin==inEnd) return NULL;
auto root = find(inBegin, inEnd, *preBegin);
TreeNode* cur = new TreeNode(*preBegin);
cur->left = recurisonBuild(preBegin+1, preBegin+1+(root-inBegin), inBegin, root);
cur->right = recurisonBuild(preBegin+1+(root-inBegin), preEnd, root+1, inEnd);
return cur;
}
面试题09. 用两个栈实现队列
题目描述
用两个栈实现一个队列。队列的声明如下,请实现它的两个函数 appendTail 和 deleteHead ,分别完成在队列尾部插入整数和在队列头部删除整数的功能。(若队列中没有元素,deleteHead 操作返回 -1 )
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/yong-liang-ge-zhan-shi-xian-dui-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
一个栈可以用于逆序输出元素,利用这样的特点可以实现队列(采用两个栈)
一个栈s1用于输入元素,一个栈用于逆序输出元素
输入直接存入栈s1,输出时首先判断s2是否存在元素,如果有则直接弹出其元素(因为该元素本身具有先入先出的顺序),否则将s1中所有元素导入s2中,再进行弹出一元素
###代码
// s1用于入栈,s2用于出栈
stack<int> s1, s2;
void appendTail(int value) {
s1.push(value);
}
int deleteHead() {
if(s2.empty()){
if(s1.empty()) return -1; // 两个栈均为空,表面该队列为空
else{
do{
s2.push(s1.top());
s1.pop();
}while(!s1.empty());
}
}
int res = s2.top();
s2.pop();
return res;
}
面试题10- I. 斐波那契数列
###题目描述
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F ( 0 ) = 0 , F ( 1 ) = 1 F ( N ) = F ( N − 1 ) + F ( N − 2 ) , 其 中 N > 1. F(0) = 0, F(1) = 1 F(N) = F(N - 1) + F(N - 2), 其中 N > 1. F(0)=0,F(1)=1F(N)=F(N−1)+F(N−2),其中N>1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
思路
经典题目,学习递归的常用例子。在leetcode中,直接采用递归法会超时。
这里采用优化的动态规划方法或者说直接套用递推公式。给定sum、a、b三个辅助变量
代码
int fib(int n) {
// 边界条件
if(n==0||n==1) return n;
int sum = 0;
int a = 0, b = 1;
for(int i = 2; i < n+1;i++){
sum = (a+b)%1000000007; // 递推公式
a = b; // 更新前数
b = sum; // 更新后数
}
return sum;
}
面试题10- II. 青蛙跳台阶问题
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
示例 1:
输入:n = 2
输出:2
示例 2:
输入:n = 7
输出:21
提示:
0 <= n <= 100
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/qing-wa-tiao-tai-jie-wen-ti-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路
重要的是打开思路,想到递归策略。
最后一步分成两种情况,一步或者两步
- 假设只需最后一步抵达第N个台阶,此时的路线数为 f ( n − 1 ) f(n-1) f(n−1)
- 假设需要两步抵达第N个台阶,此时的路线数为 f ( n − 2 ) f(n-2) f(n−2)
所以 f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(n) = f(n-1)+f(n-2) f(n)=f(n−1)+f(n−2),与Fibonacci数列的递推公式一样,区别在于初始条件。
代码
int numWays(int n) {
// 边界情况
if(n==0||n==1) return 1;
int sum=0;
int a=1, b=1;
for(int i=2; i <= n; i++){
sum = (a+b)%1000000007;
a = b;
b = sum;
}
return sum;