普通思路:先将整个链表从头到尾遍历一次,计算出链表的长度size,得到链表的长度之后,就好办了,直接输出第(size-k)个节点就可以了(注意链表为空,k

为0,k为1,k大于链表中节点个数时的情况)。时间复杂度为O(n),大概思路如下:

  1. public int findLastNode(int index) {
  2. // index代表的是倒数第index的那个结点
  3. // 第一次遍历,得到链表的长度size
  4. if (head == null) {
  5. return -1;
  6. }
  7. int size = 0;
  8. current = head;
  9. while (current != null) {
  10. size++;
  11. current = current.next;
  12. }
  13. // 第二次遍历,输出倒数第index个结点的数据
  14. current = head;
  15. for (int i = 0; i < size - index; i++) {
  16. current = current.next;
  17. }
  18. return current.data;
  19.  
  20. }

如果面试官不允许你遍历链表的长度,该怎么做呢?接下来就是。

改进思路:(这种思路在其他题目中也有应用)

这里需要声明两个指针:即两个结点型的变量first和second,首先让first和second都指向第一个结点,然后让second结点往后挪k-1个位置,此时first和second就间隔了k-1个位置,然后整体向后移动这两个节点,直到second节点走到最后一个结点的时候,此时first节点所指向的位置就是倒数第k个节点的位置。时间复杂度为O(n)

代码实现:(初版)

  1. public Node findLastNode(Node head, int index) {
  2. if (head == null) {
  3. return null;
  4. }
  5. Node first = head;
  6. Node second = head;
  7. // 让second结点往后挪index个位置
  8. for (int i = 0; i < index; i++) {
  9. second = second.next;
  10. }
  11. // 让first和second结点整体向后移动,直到second结点为Null
  12. while (second != null) {
  13. first = first.next;
  14. second = second.next;
  15. }
  16. // 当second结点为空的时候,此时first指向的结点就是我们要找的结点
  17. return first;
  18. }

代码实现:(最终版)

(考虑k大于链表中结点个数时的情况时,抛出异常)

上面的代码中,看似已经实现了功能,其实还不够健壮:

要注意k等于0的情况;

如果k大于链表中节点个数时,就会报空指针异常,所以这里需要做一下判断。

核心代码如下:

  1. public Node findLastNode(Node head, int k) {
  2. if (k == 0 || head == null) {
  3. return null;
  4. }
  5. Node first = head;
  6. Node second = head;
  7. // 让second结点往后挪k-1个位置
  8. for (int i = 0; i < k - 1; i++) {
  9. System.out.println("i的值是" + i);
  10. second = second.next;
  11. if (second == null) {
  12. // 说明k的值已经大于链表的长度了 //throw new NullPointerException("链表的长度小于" + k); //我们自己抛出异常,给用户以提示
  13. return null;
  14. }
  15. }
  16. // 让first和second结点整体向后移动,直到second走到最后一个结点
  17. while (second.next != null) {
  18. first = first.next;
  19. second = second.next;
  20. }
  21. // 当second结点走到最后一个节点的时候,此时first指向的结点就是我们要找的结点
  22. return first;
  23. }

测试代码:

  1. public static void main(String[] args) {
  2. LinkList list = new LinkList();
  3. // 向LinkList中添加数据
  4. for (int i = ; i < ; i++) {
  5. list.add(i);
  6. }
  7. list.print(list.head);// 从head节点开始遍历输出
  8. System.out.print(list.getLength(list.head));
  9. System.out.print("\r\n");
  10. // System.out.print(list.findLastNode(10));
  11. System.out.print(list.findLastNode(list.head,7).getData());
  12. System.out.print("\r\n");
  13. System.out.print(list.findMidNode(list.head).data);
  14.  
  15. }

6.查找单链表中的倒数第k个结点的更多相关文章

  1. 链表习题(8)-寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下

    /*寻找单链表中数据域大小为k的结点,并与前一结点交换,如果前一结点存在的情况下*/ /* 算法思想:定义两个指针,pre指向前驱结点,p指向当前结点,当p->data == k的时候,交换 p ...

  2. 在单链表和双链表中删除倒数第k个结点

    题目: 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 要求: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1). 解答: 让链表从头 ...

  3. [算法]在单链表和双链表中删除倒数第k个结点

    题目: 分别实现两个函数,一个可以删除单链表中倒数第K个节点,另一个可以删除双链表中倒数第K个节点. 要求: 如果链表长度为N,时间复杂度达到O(N),额外空间复杂度达到O(1). 解答: 让链表从头 ...

  4. 链表中获取倒数第K个结点

    /* * 链表中查找倒数第K个结点.cpp * * Created on: 2018年5月1日 * Author: soyo */ #include<iostream> using nam ...

  5. 链表中的倒数第k个结点

    题目描述 输入一个链表,输出该链表中倒数第k个结点.   基本思想:定义两个指针a,b分别指向头节点, a指针先向前走k-1步(注意:因为倒数节点是从倒数第一个结点开始的,而不是零),然后a指针和b指 ...

  6. 【剑指offer】链表中的倒数第k个结点

    输入一个链表,输出该链表中倒数第k个结点. 分析: 定义两个结点p1和p2都指向头节点,p1先走k-1步,然后p1和p2一起走,当p1走到链表尾部时,p2指向的结点就是倒数第k个结点 遍历一遍链表即可 ...

  7. 在单链表和双链表中删除倒数第K个节点

    [说明]: 本文是左程云老师所著的<程序员面试代码指南>第二章中“在单链表和双链表中删除倒数第K个节点”这一题目的C++复现. 本文只包含问题描述.C++代码的实现以及简单的思路,不包含解 ...

  8. 《程序员代码面试指南》第二章 链表问题 在单链表和双链表中删除倒数第K个节点

    题目 在单链表和双链表中删除倒数第K个节点 java代码 /** * @Description:在单链表和双链表中删除倒数第K个节点 * @Author: lizhouwei * @CreateDat ...

  9. python经典算法面试题1.5:如何找出单链表中的倒数第K个元素

    本题目摘自<Python程序员面试算法宝典>,我会每天做一道这本书上的题目,并分享出来,统一放在我博客内,收集在一个分类中. [微软笔试题] 难度系数:⭐⭐⭐ 考察频率:⭐⭐⭐⭐⭐ 题目描 ...

随机推荐

  1. 【论文笔记】如何理解深度学习中的End to End

    End to end:指的是输入原始数据,输出的是最后结果,应用在特征学习融入算法,无需单独处理. end-to-end(端对端)的方法,一端输入我的原始数据,一端输出我想得到的结果.只关心输入和输出 ...

  2. (转载)设计模式之-策略模式(Strategy)

    原文:http://blog.sina.com.cn/s/blog_48df74430100t2m7.html 前言 部门组织培训,<Effective Java>,每人每天给大家讲解一节 ...

  3. PHP重载以及Laravel门面Facade

    目录 重载的概念 魔术方法中的重载 属性重载 方法重载 Laravel中的Facade 扩展 谈谈__invoke Laravel提供了许多易用的Facade,让我们用起来特步顺手,那么这些Facad ...

  4. mongoDb CPU利用率100%的分析和解决

    在公司的项目中,突然出现过一个情况,mongodb 的CPU利用率到达100%,导致服务器这边卡死了,请求了半天无响应,提示请求超时. 因为,当时APP用户可能会在某一个时间段集中的使用,所以,请求量 ...

  5. NSDateFormater格式化参数汇总

    NSDateFormatterhtml, body {overflow-x: initial !important;}html { font-size: 14px; } body { margin: ...

  6. (转) MyBatis(1)——快速入门

    MyBatis 简介 MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code,并且改名为 ...

  7. 依赖注入(Dependency Injection)

    Spring的两个核心内容为控制反转(Ioc)和面向切面(AOP),依赖注入(DI)是控制反转(Ioc)的一种方式. 依赖注入这个词让人望而生畏,现在已经演变成一项复杂的编程技巧 或设计模式理念.但事 ...

  8. Go学习笔记 - 关于Java、Python、Go编程思想的不同

    ***看了两周七牛团队翻译的<Go语言程序设计>,基本上领略到了Go语言的魅力.学习一个语言,语法什么的任何人都是很容易学会,难就难在充分领略到这门编程语言的思想.*** ## 面向对象 ...

  9. Java编程的逻辑 (40) - 剖析HashMap

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  10. IDEA调试总结(设置断点进行调试)

    IDEA调试总结(设置断点进行调试) 黑背景版: 先编译好要调试的程序.1.设置断点