剑指Offer(链表的倒数第k个数值)

正常的思维都是先遍历一遍链表得到链表的长度,然后通过链表的长度减去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;	
	}
};

运行结果:


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值