面试题22:链表中倒数第k个节点.
下面的这个解法是比较容易想到的,但是存在着几个问题:没有处理节点的数目少于k的情况;没有处理k=0及k为负数的情况。在剑指offer中,k是无符号类型。输入k=0或者k=-1没有意义,可以返回空指针。如果链表的节点数少于k,那么在for循环中q会变成空指针,一旦到空指针了就表明k超过了节点的个数了,此时返回nullptr即可。
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
if(head==NULL) return NULL;
ListNode *p=head;
ListNode *q=head;//q是快指针
for(int i=0;i<k-1;i++){
q=q->next;
}
while(q->next!=NULL){
q=q->next;
p=p->next;
}
return p;
}
};
改了上面的错误后:
class Solution {
public:
ListNode* getKthFromEnd(ListNode* head, int k) {
if(head==NULL||k<=0) return NULL;
ListNode *p=head;
ListNode *q=head;//q是快指针
for(int i=0;i<k-1;i++){
if(q->next!=NULL){
q=q->next;
}
else{
return NULL;
}
}
while(q->next!=NULL){
q=q->next;
p=p->next;
}
return p;
}
};
面试题23:链表中环的入口节点
题目:如果一个链表中包含环,如何找出环的入口节点? 第一步是先确定这个链表中包含环吗。第二步是找到环的入口。
分析,如果头指针为空或者只有一个结点则直接判断为不是环形链表。如果是快指针最先到达尾部,说明不是环形链表;如果快慢指针相遇了则说明是环形链表。在有“环”的情况下,快慢指针是一定会相遇的。
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead) {
//首先判断有没有环,接着找到入口,快慢指针相遇了就说明存在环
if(pHead==NULL||pHead->next==NULL) return NULL;
ListNode* fast=pHead;
ListNode* slow=pHead;
while(1){
if(fast==NULL||fast->next==NULL){
return NULL;
}
fast=fast->next->next;
slow=slow->next;
if(slow==fast) {
break;
}
}
fast=pHead;
while(slow!=fast){
fast=fast->next;
slow=slow->next;
}
return slow;
}
};
剑指offer上给出的解法:和上面的有不同,指针p1先在链表上向前移动b步;然后指针p1和p2以相同的速度在链表上向前移动,直到它们相遇。它们相遇的结点就是环的入口节点。(即让p1先走b步,再走a步这样的话,如果链表中存在环的话就一定走到了入口节点处了!)
面试题24:反转链表
要考虑到输入的链表头指针是nullptr的情况,输入的链表只有一个结点的特殊情况。
在这道题目中需要定义三个指针,一个指向当前遍历的结点,一个指向它的前一个节点一个指向它的后一个节点。不难分析出反转后链表的头结点是原始链表的尾结点。什么节点时尾结点?自然是Next指针为空指针的结点。在我一开始写的代码中就出现了链表断裂。
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead==NULL||pHead->next==NULL) return pHead;
ListNode* pre=nullptr;
ListNode* cur=pHead;
//ListNode* pnext=pHead->next;没有必要把pnext这样写,这会儿还是可以通过cur找到它后面的结点的
while(cur!=nullptr){
ListNode* temp=cur->next;
cur->next=pre;
pre=cur;
cur=temp;
}
return pre;
}
};
还是没有很理解本题的递归解法。
面试题25:合并两个排序的链表
关于鲁棒性的问题:每当代码试图访问空指针指向的内存时程序就会崩溃,从而导致鲁棒性问题。这里回顾一下递归的解法,也是按照剑指上给出的。
提交之前先用想的一些特殊的输入来测试一下:比如两个链表的一个或两个头结点为空指针;两个链表中只有一个节点。
class Solution {
public:
ListNode* Merge(ListNode* pHead1, ListNode* pHead2) {
if(pHead1==NULL){
return pHead2;
}
else if(pHead2==NULL){
return pHead1;
}
ListNode* pMergedHead=nullptr;
if(pHead1->val<pHead2->val){
pMergedHead=pHead1;
pHead1->next=Merge(pHead1->next,pHead2);
}
else{
pMergedHead=pHead2;
pHead2->next=Merge(pHead1,pHead2->next);
}
return pMergedHead;
}
};