面试题22:链表中倒数第k个结点
题目:输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是值为4的结点。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
struct ListNode{
int value;
ListNode* next;
};
/**
* 方法一:遍历链表两次, 第一次统计出链表结点的个数, 第二次就能找到倒数第k个结点
* 缺点:需要遍历链表两次
**/
ListNode* FindKthToTail1(ListNode* pListHead, unsigned int k){
if(pListHead==NULL || k==0){
return NULL;
}
ListNode* pNode=pListHead;
int lengthOfList=0;
while(pNode){
lengthOfList++;
pNode=pNode->next;
}
if(lengthOfList<k) return NULL;
pNode=pListHead;
int cnt=0;
while(cnt!=lengthOfList-k+1){
cnt++;
pNode=pNode->next;
}
return pNode;
}
/**
* 方法二:利用两个指针, 第一个指针从链表的头指针开始遍历向前走 k-1 步,第二个指针保持不动,
* 再两个指针同时移动, 直到第一个指针到链表末尾, 第二个指针指向的元素即为所求元素
**/
ListNode* FindKthToTail2(ListNode* pListHead, unsigned int k){
if(pListHead==NULL || k==0){
return NULL;
}
ListNode* p1=pListHead;
ListNode* p2=NULL;
for(unsigned int i=0;i<k-1;i++){
if(p1->next!=NULL) p1=p1->next;
else return NULL; // 注意陷阱:一定要保证链表长度大于k
}
p2=pListHead;
while(p1->next!=NULL){
p1=p1->next;
p2=p2->next;
}
return p2;
}
int main() {
return 0;
}
相关题目:
求链表的中间节点。如果链表中的节点总数为奇数,则返回中间节点;如果节点总数是偶数,则返回中间两个节点的任意一个。为了解决这个问题,我们也可以定义两个指针,同时从链表的头节点出发,一个指针一次走一步,另一个指针一次走两步。当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
struct ListNode{
int value;
ListNode* next;
};
ListNode* FindMidOfList(ListNode* pListHead){
if(pListHead==NULL){
return NULL;
}
ListNode* p1=pListHead;
ListNode* p2=pListHead;
while(p2->next!=NULL){
p1=p1->next;
p2=p2->next;
if(p2->next!=NULL) p2=p2->next;
else break;
}
return p1;
}
int main() {
return 0;
}