正常的思维都是先遍历一遍链表得到链表的长度,然后通过链表的长度减去k得到正数第几个值。
因此我们先用简单的方法解决一下:
首先需要我们构建一个链表:我们使用尾插法进行新的节点的加入,因此我们需要创建两个节点,一个节点负责新数据的构建,一个负责链表的记录。
struct ListNode
{
int val;
struct ListNode *next;
};
首先我们需要构建一个结构体,也就是一个链表的一个节点。
然后我们来创建链表:
ListNode *L;
ListNode *r,*p;
L=new ListNode;
L->val=0;
r=L;
for (int i=1;i<10;i++)
{
p = new ListNode;
r->next=p;
p->val=i;
r=p;
}
r->next=NULL;
这里我们来解释一下链表的创建的过程:L作为一个整个链表,我们肯定需要首先创建,然后就是节点r和p了,其中r是负责记录链表的走势的,p是新节点。因此我们需要现将r指向链表一开始的L,当然这个时候L肯定为空了。
后面的关键在于r的下一个需要指向新节点p,然后r转移到当前的p的位置,接着再指向下一个p,接着又转移到下一个p,如此反复的进行,知道最后我们需要在最后加上r->next=NULL来表示链表的结束。
好了,链表创建完毕后,我们首先通过两次遍历的方法来实现一次:
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
int count=0;
ListNode *p;
p=pListHead;
if(pListHead==NULL||k==0)
return NULL;
while(p!=NULL)
{
p=p->next;
count++;
}
if(count<k)
return NULL;
p=pListHead;
for(int i=0;i<(count-k);i++)
p=p->next;
return p;
}
};
其基本思路是:先遍历真个链表得到链表的长度count,然后判断count和k的大小,如果小于k,那就说明k的取值越界了。之后只要移动count-k位就行了。
其实还有一种只遍历一次的方法:使用两个节点,一个读取k-1步,然后第二个再开始读取,这个时候两个节点同时移动,当第一个节点移动到链表的结尾时,第二个节点的位置就是倒数第k个节点的位置。
这里我们需要注意的是为什么要先走到k-1步,我们可以假设链表的长度为n,那么第一个节点走到k-1的位置时,第二个节点开始移动,那么第二个节点移动的长度便是n-k+1。我们可以用一个例子来解释一下,加入链表为{1,2,3,4,5,6,7,8,9},k=3,n=9,第一个节点需要先走2步到达2,然后第二个节点和第一个节点一起同时走,需要走7步,第一个节点到达链表的尾部9,第二个节点到达链表的第7位,即为7。
实现代码:
class solution
{
public:
ListNode* FindKthToTail(ListNode *pListHead,unsigned int k)
{
if(pListHead==NULL||k==0)
return NULL;
int count=0;
ListNode *r,*p;
r=pListHead;
p=pListHead;
for(int i=1;i<k;i++)
{
if(r->next==NULL)
return NULL;
else
r=r->next;
}
while(r->next!=NULL)
{
r=r->next;
p=p->next;
}
return p;
}
};
运行结果: