剑指offer系列8:链表中倒数第k个结点

看到这个题我有两个思路

1.遍历链表得到长度n,判断n与k的关系,若n>k,返回空,其他情况下输出n-k个结点的信息

2.将链表数据压栈,然后弹出k个。

这道题返回的是链表结点,所以方法2不行,2只能在求数据的时候可以。给出我的思路的代码:

 1 #include<iostream>
 2 
 3 using namespace std;
 4 struct ListNode {
 5 int val;
 6 struct ListNode *next;
 7 /*                                 //为什么不屏蔽这部分会报错没有默认的析构函数?
 8 ListNode(int x) :
 9 val(x), next(NULL) {
10 }
11 */
12 };
13 class Solution {
14 public:
15     ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
16         if (pListHead->next == NULL)          //没考虑到这种情况,看答案想起来的
17             return NULL;
18         ListNode *p = pListHead;
19         int count = 0;
20         while (p->next != NULL)
21         {
22             count++;
23             p = p->next;
24         }
25         count = count+1;
26         //cout << count << endl;
27         int n = 0;                       //本来在35行直接计算的,以防越界我设置了变量n
28         if (k > count)
29         {
30             return NULL;
31         }
32         else
33         {
34             n = count - k;
35             //pListHead = pListHead +n ;
36             for (int i = 0; i < n; i++)
37                 pListHead = pListHead->next;
38         }
39         return pListHead;
40     }
41 };
42 int main()
43 {
44     Solution so;
45     ListNode list[4];
46     list[0].val = 1;
47     list[0].next = &list[1];
48     list[1].val = 2;
49     list[1].next = &list[2];
50     list[2].val = 3;
51     list[2].next = &list[3];
52     list[3].val = 4;
53     list[3].next = NULL;
54     cout << so.FindKthToTail(list, 1)->val << endl;
55     return 0;
56 }

看35行,本来我是这么得到相应的结点的,但是这样我在vs里面run没有问题,上交到牛客网提示报错说数组越界,堆栈溢出,我想问题是不是我定义的是链表,对于链表数据的存储是不按照物理内存的位置而定的。所以我对链表首个结点不能进行+和减得操作。我在我的代码因为我定义的链表为了方便是特殊的结构体数组的形式,所以我的测试用例的链表内存之间是相邻的,可是牛客网上测试用例的链表物理内存不相邻,因此发生了数组越界。正确的应该是用for循环,链表访问第k个结点只能用for循环的方式!

关于.访问和->访问,.访问的左侧是对象,->访问的左侧是指针。

下面是根据答案写出来,答案的思路很高效,根本不需要先遍历一遍。而是设置两个指针分别是right和left。最开始两个指针都指向链表的头指针,然后给right指向k-1个结点,在将right和left同步向后一个结点移动,知道right移动到NULL时,left的位置就所求的答案。这样只需要遍历一遍链表即可。下面给个这个思路的代码:

 1 class Solution {
 2 public:
 3     ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
 4         if (pListHead == NULL)                   //这句开始写成了这个指针的next不为空,报错了,记住传指针的函数一定要判断该指针是否为空
 5             return NULL;
 6         ListNode *r = pListHead;
 7         ListNode *l = pListHead;
 8         int i = 0;
 9         while (i < k-1&&r!= NULL)
10         {
11             i++;
12             r = r->next;
13         }
14         if (r == NULL)
15             return NULL;
16         else
17         {
18             while (r->next !=NULL)
19             {
20                 r = r->next;
21                 l = l->next;
22 
23             }
24         }
25         return l ;
26     }
27 };

总结一下这道题,关于链表是只能顺序访问的,所以各种题目总是喜欢让你反着访问链表的值。这种情况双指针是很好的办法。

在分析每一道题时,首先要考虑到数的边界问题,考虑到传入的值得安全性,再去做相应的处理,不要默认传入的值都是符合要求的,思路一定要全面。

原文地址:https://www.cnblogs.com/neverland0718/p/10986923.html