分析:
首先,這道題考察了程序的魯棒性,主要是關於空指針以及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;
}
};
擴展:尋找鏈表的中間節點
分析:我們可以定義兩個指針,同時從鏈表的頭結點出發,一個指針一次走一步,另一個指針一次走兩步,當走得快的指針走到鏈表的末尾時,走得慢的指針正好在鏈表的中間。
當我們用一個指針遍歷鏈表不能解決問題的時候,可以嘗試用兩個指針來遍歷鏈表。