Java实现链表中倒数第k个结点

简介: 链表中倒数第k个结点输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是值为4的结点。

链表中倒数第k个结点

输入一个链表,输出该链表中倒数第k个结点。为了符合大多数人的习惯,本题从1开始计数,即链表的尾结点是倒数第1个结点。例如一个链表有6个结点,从头结点开始它们的值依次是1、2、3、4、5、6。这个链表的倒数第3个结点是值为4的结点。

package last;
import java.util.Stack;
/**
 * @author kegekeqi
 * @version 1.0
 * @date 2022-1-18 7:49
 */
public class KLastNode {
  public static class ListNode {
    int val;
    ListNode next = null;
    ListNode(int val) {
      this.val = val;
    }
  }
  //方法一 利用栈
  public ListNode findKthToTail1(ListNode head, int k) {
    if (null == head || k <= 0) {
      return null;
    }
    int numbOfList = 1;
    Stack<ListNode> st = new Stack<ListNode>();
    st.push(head);
    ListNode node = head.next;
    while (null != node) {
      numbOfList ++;
      st.push(node);
      node = node.next;
    }
    if (k > numbOfList) {
      return null;
    } else {
      for (int i = 1; i <= k; i++) {
        node = st.pop();
      }
      return node;
    }
  }
  //方法2:利用两个相距为k-1的指针
  public ListNode FindKthToTail2(ListNode head, int k) {
    if (head == null || k <= 0) {
      return null;
    }
    ListNode pAhead = head;
    for (int i = 1; i < k; i++) {
      pAhead = pAhead.next;
      if (pAhead == null) {
        return null;
      }
    }
    ListNode pBehind = head;
    while (pAhead.next != null) {
      pAhead = pAhead.next;
      pBehind = pBehind.next;
    }
    return pBehind;
  }
  void test1() {
    ListNode head=null;
    ListNode result=FindKthToTail2(head, 1);
    if (result==null) {
      System.out.println("test1 passed!");
    } else {
      System.out.println("test1 failed!");
    }
  }
  /*
   * k超出范围
   */
  void test2() {
    ListNode head=new ListNode(2);
    ListNode result=FindKthToTail2(head, 2);
    if (result==null) {
      System.out.println("test2 passed!");
    }
    else {
      System.out.println("test2 failed!");
    }
  }
  /*
   * 单个结点
   */
  void test3() {
    ListNode head=new ListNode(1);
    ListNode result=FindKthToTail2(head, 1);
    if(result.val==1) {
      System.out.println("test3 passed!");
    }
    else {
      System.out.println("test3 failed!");
    }
  }
  /*
   * 尾结点
   */
  void test4() {
    ListNode node1=new ListNode(1);
    ListNode node2=new ListNode(2);
    ListNode node3=new ListNode(3);
    ListNode node4=new ListNode(4);
    node1.next=node2;
    node2.next=node3;
    node3.next=node4;
    ListNode result=FindKthToTail2(node1, 1);
    if(result.val==4) {
      System.out.println("test4 passed!");
    }
    else {
      System.out.println("test4 failed!");
    }
  }
  /*
   * 中间结点
   */
  void test5() {
    ListNode node1=new ListNode(1);
    ListNode node2=new ListNode(2);
    ListNode node3=new ListNode(3);
    ListNode node4=new ListNode(4);
    node1.next=node2;
    node2.next=node3;
    node3.next=node4;
    ListNode result=FindKthToTail2(node1, 2);
    if(result.val==3) {
      System.out.println("test5 passed!");
    }
    else {
      System.out.println("test5 failed!");
    }
  }
  /*
   * 头结点
   */
  void test6() {
    ListNode node1=new ListNode(1);
    ListNode node2=new ListNode(2);
    ListNode node3=new ListNode(3);
    ListNode node4=new ListNode(4);
    node1.next=node2;
    node2.next=node3;
    node3.next=node4;
    ListNode result=FindKthToTail2(node1, 4);
    if(result.val==1) {
      System.out.println("test6 passed!");
    }else {
      System.out.println("test6 failed!");
    }
  }
  public static void main(String[] args) {
    KLastNode demo = new KLastNode();
    demo.test1();
    demo.test2();
    demo.test3();
    demo.test4();
    demo.test5();
    demo.test6();
  }
}
相关文章
|
4天前
|
算法
LeetCode第19题删除链表的倒数第 N 个结点
该文章介绍了 LeetCode 第 19 题删除链表的倒数第 N 个结点的解法,通过使用快慢双指针,先将快指针移动 n 步,然后快慢指针一起遍历,直到快指针到达链尾,从而找到倒数第 N 个结点的前一个结点进行删除,同时总结了快慢指针可减少链表遍历次数的特点。
LeetCode第19题删除链表的倒数第 N 个结点
|
6天前
|
存储 Java
java实现单链表的创建、增、删、改、查
这篇文章详细介绍了Java中如何实现单链表的创建以及对单链表进行增加、删除、修改、查询等操作的方法,并提供了相应的代码示例。
java实现单链表的创建、增、删、改、查
|
6天前
【刷题记录】链表的中间结点
【刷题记录】链表的中间结点
|
6天前
|
存储 Java
java实现双向链表的增删改查
这篇文章展示了如何在Java中实现双向链表的增加、删除、修改和查询操作,并通过代码示例演示了在双向链表中存储和操作学生信息的过程。
|
11天前
|
算法 Java
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
LeetCode初级算法题:环形链表+排列硬币+合并两个有序数组java解法
18 0
|
11天前
|
存储 算法 Java
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
10 0
|
7天前
|
Java 开发者
奇迹时刻!探索 Java 多线程的奇幻之旅:Thread 类和 Runnable 接口的惊人对决
【8月更文挑战第13天】Java的多线程特性能显著提升程序性能与响应性。本文通过示例代码详细解析了两种核心实现方式:Thread类与Runnable接口。Thread类适用于简单场景,直接定义线程行为;Runnable接口则更适合复杂的项目结构,尤其在需要继承其他类时,能保持代码的清晰与模块化。理解两者差异有助于开发者在实际应用中做出合理选择,构建高效稳定的多线程程序。
28 7
|
6天前
|
安全 Java 数据库
一天十道Java面试题----第四天(线程池复用的原理------>spring事务的实现方式原理以及隔离级别)
这篇文章是关于Java面试题的笔记,涵盖了线程池复用原理、Spring框架基础、AOP和IOC概念、Bean生命周期和作用域、单例Bean的线程安全性、Spring中使用的设计模式、以及Spring事务的实现方式和隔离级别等知识点。
|
6天前
|
存储 监控 安全
一天十道Java面试题----第三天(对线程安全的理解------>线程池中阻塞队列的作用)
这篇文章是Java面试第三天的笔记,讨论了线程安全、Thread与Runnable的区别、守护线程、ThreadLocal原理及内存泄漏问题、并发并行串行的概念、并发三大特性、线程池的使用原因和解释、线程池处理流程,以及线程池中阻塞队列的作用和设计考虑。
|
3天前
|
存储 缓存 安全
深度剖析Java HashMap:源码分析、线程安全与最佳实践
深度剖析Java HashMap:源码分析、线程安全与最佳实践