分析:
首先,这道题考察了程序的鲁棒性,主要是关于空指针以及k的取值问题
第一种思路:可以使用一个栈来实现,由于栈是后进先出的一种数据结构,我们可以将遍历链表的节点存储到栈中,接着弹栈k次即可得到倒数第k个节点。
第二种思路:双指针
我们考虑设置两个指针,开始时都指向头结点,第一个指针向前移动k-1次,这样它就到达了第k个节点,第二个指针指向头结点,它们相距k-1步,接着同时移动两个指针,直至第一个指针指向尾节点,这样第二个指针就指向倒数第k个节点。
栈:
//可以把链表放到栈中,然后逆向弹出第k个元素即为倒数第k个节点
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead==nullptr) return nullptr;
stack<ListNode*>solve;
while(!solve.empty()) solve.pop();
ListNode* pNode = new ListNode(-1);
pNode = pListHead;
while(pNode!=nullptr)
{
solve.push(pNode);
pNode = pNode->next;
}
ListNode* num = new ListNode(-1);
if(k>solve.size()||k==0) return nullptr;
while(k--)
{
num = solve.top();
solve.pop();
}
return num;
}
};
双指针:
//第一种思路:是使用一个栈来储存链表从前向后遍历的节点,然后经历k次弹栈即可
//第二种思路:使用双指针,设置两个指针,首先都指向头结点,接着第一个指针向前移动k步
//那么第二个指针与第一个指针相差k-1步,这样,当第一个指针指向尾节点,那么第二个指针就指向解
//第二种方法比较巧妙
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(pListHead==nullptr||k==0) return nullptr;
ListNode* First = pListHead;
ListNode* Second = pListHead;
for(int i=0;i<k-1;i++)
{
First = First->next;
if(First==nullptr) return nullptr;
}
while(First->next!=nullptr)
{
First = First->next;
Second = Second->next;
}
return Second;
}
};
扩展:寻找链表的中间节点
分析:我们可以定义两个指针,同时从链表的头结点出发,一个指针一次走一步,另一个指针一次走两步,当走得快的指针走到链表的末尾时,走得慢的指针正好在链表的中间。
当我们用一个指针遍历链表不能解决问题的时候,可以尝试用两个指针来遍历链表。