倒转链表中第k个结点
法一:双指针移动
这题要求链表的倒数第k个节点,最简单的方式就是使用两个指针,第一个指针先移动k步,然后第二个指针再从头开始,这个时候这两个指针同时移动,当第一个指针到链表的末尾的时候,返回第二个指针即可。注意,如果第一个指针还没走k步的时候链表就为空了,我们直接返回null即可。
class Solution {
public:
ListNode* FindKthToTail(ListNode* pHead, int k) {
if(pHead==NULL) return NULL;
ListNode* first=pHead;
ListNode* second=pHead;
while(k--){
if(first==NULL) return NULL;
first=first->next;
}
while(first != NULL){
first=first->next;
second=second->next;
}
return second;
}
};
法二:用栈解决
class Solution {
public:
ListNode* FindKthToTail(ListNode* pHead, int k) {
if(pHead==NULL) return NULL;
stack<ListNode*> v;
int count=0;
while(pHead!=NULL){
v.push(pHead);
pHead=pHead->next;
count++;
}
ListNode* FirstNode=v.top();
v.pop();
ListNode* temp;
if(count<k||k==0) return NULL;
for(int i=1;i<k;i++){
temp=v.top();
temp->next=FirstNode;
FirstNode=temp;
v.pop();
}
return FirstNode;
}
};
法三:递归返回
终止条件很明显就是当节点head为空的时候,就没法递归了,这里主要看的是逻辑处理部分,当递归往下传递到最底端的时候,就会触底反弹往回走,在往回走的过程中记录下走过的节点,当达到k的时候,说明到达的那个节点就是倒数第k个节点,直接返回即可,如果没有达到k,就返回空,搞懂了上面的过程,代码就很容易写了
class Solution {
int cnt=0;//全局变量,记录递归往回走时访问的结点数量
public:
ListNode* FindKthToTail(ListNode* pHead, int k) {
//边界条件判断
if(pHead==NULL) return NULL;
ListNode* node=FindKthToTail(pHead->next,k);
++cnt;
//从后往前数结点数小于k,返回空
if(cnt<k){
return NULL;
}else if(cnt==k){
//从后往前数结点数等于k,返回空当前传递进来的pHead
return pHead;
}else{//如果要返回倒数第0个结点,就需要这个条件来判断
//注意此处不能省略cnt>k的情况,编译器会认为可能存在cnt>k的情况而出错
//从后往前数结点数大于k,返回node
return node;
}
}
};
上面代码在仔细一看,当size小于k的时候node节点就是空,所以我们可以把size大于k和小于k合并为一个,这样代码会更简洁一些
class Solution {
int cnt=0;
public:
ListNode* FindKthToTail(ListNode* pHead, int k) {
if(pHead==NULL) return NULL;//即作为判断是否为空条件,也为递归跳出条件
ListNode* node=FindKthToTail(pHead->next,k);
if((++cnt) == k) return pHead;
return node;
}
};