22 链表中倒数第k个节点(第3章 高质量的代码-代码的鲁棒性)

题目描述:

输入一个链表,输出该链表中倒数第k个结点。

尾节点是倒数第一个节点

测试用例:  

功能测试(第k个节点在中间、是头节点、是尾节点)

特殊输入测试(链表头节点是nullptr指针、链表的头节点个数小于k、k=0)

解题思路:

1)使用两个指针,一个指针先移动k步,如果链表小于k,终止返回nullptr。然后两个指针同时移动,知道后一个指针移出最后一个节点

//实现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;  //不要忘记k<0的情况  无符号不用判断k<0时;

        ListNode* back = pListHead;
        //先将指针back移动到第k个元素的位置,索引k的位置
        while(back!=nullptr && k>0){ //先判断k=0,然后才是k--。
            back=back->next;
            k--;
        }
        if(k>0) //说明链表的长度<k
            return nullptr;

        ListNode* front = pListHead;
        while(back!=nullptr){ //back->next!=nullptr 是错误的。
            back=back->next;
            front=front->next;
        }

        return front;
    }
};  

注:尾节点是倒数第一个节点,因此k=1时,front应该指向尾节点,此时back应该是刚好移出尾节点,为空nullptr。

使用两个指针,一个指针先移动k-1步,如果链表小于k,终止返回nullptr。然后两个指针同时移动,知道后一个指针移动到最后一个节点

//实现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;  //无符号,所以不用判断k<0;

        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置,
        while(back->next!=nullptr && k-1>0){ //为了得知第k个元素是否存在,应该判断back->next!=nullptr而不是back!=nullptr
            back=back->next;
            k--;
        }
        if(k>1) //说明链表的长度<k
            return nullptr;

        ListNode* front = pListHead;
        while(back->next!=nullptr){ //back移动到最后一个元素即可
            back=back->next;
            front=front->next;
        }

        return front;
    }
};
//实现2
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==nullptr || k==0)return nullptr;  //无符号,所以不用判断k<0;

        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置,
        /*while(back->next!=nullptr && k-1>0){ //为了得知第k个元素是否存在,应该判断back->next!=nullptr而不是back!=nullptr
            back=back->next;
            k--;
        }
        if(k>1) //说明链表的长度<k
            return nullptr;*/
        for(unsigned int i=0;i<k-1;++i){
            if(back->next!=nullptr)
                back=back->next;
            else
                return nullptr;
        }

        ListNode* front = pListHead;
        while(back->next!=nullptr){ //back移动到最后一个元素即可
            back=back->next;
            front=front->next;
        }

        return front;
    }
};

    

对于unsigned int类型要格外注意,在写循环或者判断时,常会遇到对变量--;这种情况要格外注意:

因为当unsigned int k=0; --k后,变量的值并不是-1,而是无符号的0xFFFFFFFF,如果此时判断k>0,还是会成立

//该方法是错误的,当k=0是,K-1为0xFFFFFFFF,back会一直向后访问超出数组
class Solution {
public:
    ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
        if(pListHead==nullptr || k<0)return nullptr;

        ListNode* back = pListHead;
        //先将指针back移动到第k-1个元素的位置
       for(unsigned int i=0; i<k-1; ++i){
            bask=back->next;
        }

        if(k>1) //说明链表的长度<k
            return nullptr;

        ListNode* front = pListHead;
        //back移动到最后一个元素
        while(back->next!=nullptr){ //back->next!=nullptr
            back=back->next;
            front=front->next;
        }

        return front;
    }
};

  

相似题目:

求链表的中间节点:如果链表中的节点总数为奇数,则返回中间节点;如果链表总数是偶数,则返回中间两个节点的任意一个。

为了解决这个问题,也可以同时定义两个指针,同时从链表出发,一个指针一次走一步,另一个指针一次走两步。当走的快的指针走到链表末尾时,走的慢的指针正好在链表的中间。

原文地址:https://www.cnblogs.com/GuoXinxin/p/10447460.html

时间: 2024-11-12 04:55:09

22 链表中倒数第k个节点(第3章 高质量的代码-代码的鲁棒性)的相关文章

剑指OFFER----面试题22. 链表中倒数第k个节点

链接:https://leetcode-cn.com/problems/lian-biao-zhong-dao-shu-di-kge-jie-dian-lcof/ 代码: /** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public:

剑指offer-第三章高质量的代码(输出该链表中倒数第K个节点)

题目:输入一个链表,输出这个链表中倒数第K个节点.(代码的鲁棒性) 思路:用两个指针p1和p2,都指向头节点,开始的时候,p2不动,p1移动k-1次,指向第k个节点.此时,如果p1->next!=null,则同时移动P1和p2.直到p1指向最后一个节点.此时,P2指向倒数第k个节点. C++代码: #include<iostream> using namespace std; struct ListNode { int m_nValue; ListNode* m_pNext; }; Li

C++ 算法之 链表中倒数第k个节点

题目:输入一个链表,输出链表中倒数第k个节点,为了符合大多数人的习惯,本题从1开始计数,即链表的尾巴节点是倒数第一个节点. 方法1:先遍历链表得到链表的个数n,倒数第k个节点就是n-k+1再遍历一次链表,找到第n-k+1个节点就是倒数第k个节点:这种方法遍历两次链表: 方法2:先遍历链表把链表压入一个栈,再出栈,第k次出栈就是第k个节点: 方法3:先反转链表,再遍历 方法4:定义两个指针,第一个指针从链表的头指针开始遍历向前走k-1:第二个指针保持不动,从第k步开始,第二个指针也开始遍历,两个指

经典算法学习——链表中倒数第k个节点

这是剑指Offer中非常经典的一道题,也是在面试笔试中高频出现.题目的详细描述如下:输入一个链表,输出该链表中倒数第k个节点.为了符合大多数人的习惯,从1开始计数,即链表的尾结点是倒数第一个节点. 本题有一个非常直观的解法,就是对链表扫描两遍,第一遍用来记录链表长度为n,第二次从链表头部走(n-k+1)步后,找到的那个节点就是倒数第k个节点.这种算法的问题就是需要扫描链表两遍,显得不是特别聪明. 其实多想想,这个算法模型和栈的形式非常像,我们只要从头开始扫描链表,把扫描到的每一个节点放入栈中,扫

删除单链表中倒数第 k 个节点

思路 1 :两个指针 p1 ,p2 ,p1从头开始遍历,当 p1 到达第 k 个节点时,p2 开始: 当 P1 到达链表的最后一个节点时,p2 所指的节点则为链表中倒数第 k 个节点. public class Node{ public int data; public Node next; public Node(int data){ this.data = data; } public Node removeLastKNode(Node head,int k){ if(head == nul

14 链表中倒数第K个节点 FindKthToTail

输入一个链表,输出该链表中倒数第k个结点. 核心思想: 两个指针,先让第一个指针和第二个指针都指向头结点,然后再让第一个指正走(k-1)步,到达第k个节点. 然后两个指针同时往后移动,当第一个结点到达末尾的时候,第二个结点所在位置就是倒数第k个节点了 时间复杂度O(n),一次遍历即可 1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val;

链表中倒数第K个节点

输入一个链表,输出该链表中倒数第k个结点. class ListNode { int val; ListNode next = null; ListNode(int val) { this.val = val; }} public class Solution { public ListNode FindKthToTail(ListNode head,int k) { ListNode pre=null,p=null; //两个指针都指向头结点 p=head; pre=head; //记录k值

【Java】 剑指offer(22) 链表中倒数第k个结点

正文 本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集   题目 输入一个链表,输出该链表中倒数第k个结点.为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点.例如一个链表有6个结点,从头结点开始它们的值依次是1.2.3.4.5.6.这个链表的倒数第3个结点是值为4的结点. 思路 第一直觉是先从头开始遍历,计算链表个数n,然后重新遍历,第n-k+1个结点即为所需要的结点.但是需要遍历2次.后面采用了栈进行实现该

14.链表中倒数第k个节点

题目描述: ??输入一个链表,输出该链表中倒数第k个结点. 思路分析: ??设置两个指针,一个fast一个slow,都从链表头开始,让fast先走k步,然后两个指针一起走,当fast走到尾部,那么slow指针指向的就是倒数第K个节点. 代码: public class Solution { public ListNode FindKthToTail(ListNode head,int k) { ListNode fast=head; ListNode slow=head; if(head==nu