Day6-学习内容:
(1)剑指Offer
面试题10:斐波那契数列
面试题17:打印从1到最大的n位数
(2)leetcode
例1:链表排序
例2:判断链表是否含有环
1.剑指Offer
面试题10:斐波那契数列
题目描述:
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0),n<=39。
思路:
(1)递归-大量重复计算、效率低(不可取)
(2)循环实现递归思想-存储中间过程避免重复计算、时间复杂度O(n)(OK)
(3)基于递归的O(n)求n次方-参考面试题16“数值的整数次方”(OK)
代码:c++实现,基于思路(2)(已通过调试!)
class Solution {
public:
int Fibonacci(int n) {
if(n>39||n<0){
return false;
}
int f1=0;
int f2=1;
int fn=0;
if(n==0){
return f1;
}
else if(n==1){
return f2;
}
else{
for(int i=2;i<=n;i++){
fn=f1+f2;
f1=f2;
f2=fn;
}
}
return fn;
}
};
总结:加强基于斐波那契数组的应用实践比如“青蛙跳台阶”、“使用2*1的小矩形横竖覆盖更大矩形”等诸多问题。
面试题17:打印从1到最大的n位数
题目描述:
输入数字n,按顺序打印出从1到最大的n位十进制数。
思路:
(1)先求出最大的n位数,使用循环逐一打印-没有考虑大数问题,最大n位数可能会造成整型或长整型(long long)溢出(不可取)
(2)字符串上模拟数字加法(可取,但时间有限不好实现)
solution:1.在字符串上模拟加法,用Increment()函数实现
2.把字符串表达的数字打印出来
注意点:(1)如何在每次增加1时快速判断当前数字是否达到了最大的n位数,使得时间复杂度O(n).
(2)能否按阅读习惯打印出数字,即对于n位数的字符串如何实现从第一个非0字符开始打印。
(3)采用数字排列解法,递归实现(可取,且代码简洁)
代码:C++实现,基于思路(3),书上解法,牛客网上无对应例题故暂未调试。
1 void Print1ToMaxOfNDigits(int n){
2 if(n<=0){
3 return;
4 }
5 char *number=new char[n+1];
6 number[n]='\0';
7 for(int i=0;i<10;i++){
8 number[0]= i+'0';
9 Print1ToMaxOfNDigitsRecursively(number,n,0);
10 }
11 delete []numbers;
12 }
14 void Print1ToMaxOfNDigitsRecursively(char *number,int length,int index){
15 if(index==length-1){
16 PrintNumber(number);
17 return;
18 }
19 for(int i=0;i<10;++i){
20 number[index+1]=i+'0';
21 Print1ToMaxOfNDigitsRecursively(number,length,index+1);
22 }
23 }
24 void PrintNumber(char *number){
25 bool isBeginning0=true;
26 int nLength=strlen(number);
27 for(int i=0;i<nLength;++i){
28 if(isBeginning0&&number[i]!=0){
29 isBeginning0=false;
30 }
31 if(!isBeginning0){
32 printf("%c",number[i]);
33 }
34 }
35 printf("\t");
2.Leetcode
例1:链表排序
题目描述:Sort a linked list in O(n log n) time using constant space complexity.
思路:(1)快慢指针+归并排序
(2)因为题目要求复杂度为O(nlogn),故可以考虑归并排序的思想。
归并排序的一般步骤为:
1)将待排序数组(链表)取中点并一分为二;
2)递归地对左半部分进行归并排序;
3)递归地对右半部分进行归并排序;
4)将两个半部分进行合并(merge),得到结果。
代码:(已调试通过!)
class Solution {
public:
ListNode *sortList(ListNode *head) {
if (!head || !head->next) return head;
ListNode* p = head, *q = head->next;
while(q && q->next) {
p = p->next;
q = q->next->next;
}
ListNode* right = sortList(p->next);
p->next = NULL;
ListNode* left = sortList(head);
return merge(left, right);
}
ListNode *merge(ListNode *left, ListNode *right) {
ListNode dummy(0);
ListNode *p = &dummy;
while(left && right) {
if(left->val < right->val) {
p->next = left;
left = left->next;
}
else {
p->next = right;
right = right->next;
}
p = p->next;
}
if (left) p->next = left;
if (right) p->next = right;
return dummy.next;
}
};
例2:判断链表是否含有环
题目描述:
Given a linked list, return the node where the cycle begins. If there is no cycle, returnnull.
Follow up:
Can you solve it without using extra space?
思路:
1.首先判断是否存在环
2.若存在环,则从起点开始,每走一步就删除上一个节点的next指针,最后一个节点就是环的起点。因为环的起点会存在两个next指向它。
代码:(已调试通过!)
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(!head||!head->next){
return NULL;
}
ListNode *fast=head;
ListNode *slow=head;
while(fast&&fast->next){
fast=fast->next->next;
slow=slow->next;
if(fast==slow){
break;
}
}
if(!fast||!fast->next){
return NULL;
}
ListNode *pre=head;
ListNode *cur=head->next;
while(cur){
if(pre==cur){
return pre;
}
pre->next=NULL;
pre=cur;
cur=cur->next;
}
return pre;
}
};