递归关键:递推公式
递推公式关键:
要解决问题A,假设子问题B、C已经解决,然后看如何利用B、C来解决A。
先罗列一下,晚点记得补各种思路优劣和细节。
1.面试题07. 重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
struct TreeNode*rebuild(int* preorder,int* inorder,int head,int in_left,int in_right){
int i;
if(in_left > in_right) return NULL;
struct TreeNode* Node = (struct TreeNode*)malloc(sizeof(struct TreeNode));
memset(Node,0,sizeof(struct TreeNode));
Node->val = preorder[head];
while(Node->val != inorder[i]) i++;
Node->left = rebuild(preorder,inorder,head+1,in_left,i-1);
Node->right = rebuild(preorder,inorder,head+i-in_left+1,i+1,in_right);
return Node;
}
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
struct TreeNode*rootNode = (struct TreeNode*)malloc(sizeof(struct TreeNode));
int in_left = 0;
int in_right = inorderSize - 1;
memset(rootNode,0,sizeof(struct TreeNode));
rootNode = rebuild(preorder,inorder,0,in_left,in_right);
return rootNode;
}
2.面试题10- I. 斐波那契数列
写一个函数,输入 n ,求斐波那契(Fibonacci)数列的第 n 项。斐波那契数列的定义如下:
F(0) = 0, F(1) = 1
F(N) = F(N - 1) + F(N - 2), 其中 N > 1.
斐波那契数列由 0 和 1 开始,之后的斐波那契数就是由之前的两数相加而得出。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
递归优化思路:①避免重复计算,将计算过的值存入数组或hashMap,直接查表取用。
②自顶向下变自顶向上,递归变递推。
int fib(int n){
/*if(n <= 1) return n; //递归结束条件
return fib(n - 1)+fib(n - 2); //递归关系式
*/
if(n == 0||n == 1) return n;
int num1 = 0;
int num2 = 1;
int tem = 0;
while(--n)
{
tem = (num1+num2)%1000000007;
num1 = num2;
num2 = tem;
}
return num2;
}
面试题10- II. 青蛙跳台阶问题
题目描述
一只青蛙一次可以跳上1级台阶,也可以跳上2级台阶。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
(0级台阶1种跳法)
思路:
对于n级台阶,一只青蛙第一次可以跳上1级台阶,也可以跳上2级台阶。
若跳上1级台阶,则接下来有f(n-1)种跳法。
若跳上2级台阶,则接下来有f(n-2)种跳法。
故对于n级台阶,共有f(n-1)+ f(n-2)种跳法。
转化为斐波那契数列问题。有递归和动态规划两种解法。
int numWays(int n){
/*if(n <= 1) return 1;
return numWays(n-1)+numWays(n-2); //递归超时
*/
if(n <= 1) return 1;
int tem = 0;
int numWays1 = 1;
int numWays2 = 1;
while(--n){
tem = numWays2;
numWays2 = (numWays1 + numWays2)%1000000007;
numWays1 = tem;
}
return numWays2;
}
面试题24. 反转链表
题目描述
定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
递归思路:
①递归函数功能:反转链表
②结点的下一个结点为空时,递归终止
③等价关系:head为头结点时,调用本函数(传参为head->next),得到5->4->3->2 <-1
将2指向1,即完成函数功能:head->next->next = head;
双指针法:
使用两个指针,进行局部交换,交换后指针前进。
防止后续链表丢失,可用一个局部变量暂存。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
//我写的,不够简洁,return值不同导致不能直接返回尾结点
/*struct ListNode* reverseNode(struct ListNode* Node){
if(Node->next == NULL) return Node;
struct ListNode* temNode = reverseNode(Node->next);
temNode->next = Node;
Node->next = NULL;
return Node;
}
struct ListNode* reverseList(struct ListNode* head){
if(head == NULL) return NULL;
struct ListNode* newHead = head;
for(newHead;newHead->next;newHead = newHead->next);
reverseNode(head);
return newHead;
}*/
//简洁版递归
/*
struct ListNode* reverseList(struct ListNode* head){
if(head == NULL||head->next == NULL) return head; //递归终止条件
struct ListNode* temp = reverseList(head->next); //存下尾结点用于返回
head->next->next = head;
head->next = NULL; //改变指针指向
return temp;
}*/
//双指针法
struct ListNode* reverseList(struct ListNode* head){
if(head == NULL) return head;
struct ListNode* N1 = NULL;
struct ListNode* N2 = head;
while(N2)
{
struct ListNode* temp = N2->next;
N2->next = N1;
N1 = N2;
N2 = temp;
}
return N1;
}
/虽然是简单题,一遍过还是有点开心的(●’◡’●)/