博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面试 8:快慢指针法玩转链表算法面试(二)
阅读量:5877 次
发布时间:2019-06-19

本文共 3822 字,大约阅读时间需要 12 分钟。

昨天在最后给大家留了拓展题,不知道大家有没有思考完成,其实南尘说有巨坑是吓大家的啦,实际上也没什么。我们来继续看看昨天这个拓展题。

面试题:给定单链表的头结点,删除单链表的倒数第 k 个结点。

前面的文章见链接:面试 7:面试常见的链表算法捷径(一)

这个题和前面的文章中增加了一个操作,除了找出来这个结点,我们还要删除它。删除一个结点,想必大家必定也知道:要想操作(添加、删除)单链表的某个结点,那我们还得知道这个节点的前一个节点。所以我们要删除倒数第 k 个结点,就必须要找到倒数第 k+1 个结点。然后把倒数第 k+1 个元素的 next 变量 p.next 指向 p.next.next。

我们找到倒数第 k 个结点的时候,先让 fast 走了 k-1 步,然后再让 slow 变量和 fast 同步走,它们之间就会一直保持 k-1 的距离,所以当 fast 到链表尾结点的时候,slow 刚刚指向的是倒数第 k 个结点。

本题由于我们要知道倒数第 k+1 个结点,所以得让 fast 先走 k 步,待 fast 指向链表尾结点的时候,slow 正好指向倒数第 k+1 个结点。

我们简单思考一下临界值:

  1. 当 k = 1 的时候,删除的值是尾结点。我们让 fast 先走 1 步,当 fast.next 为尾结点的时候,倒数第 k+1 个结点正好是我们的倒数第二个结点。我们删除 slow.next,并让slow.next 指向 slow.next.next = null,满足条件。
  2. 当 k > len 的时候,我们要找的倒数第 k 个元素不存在,直接出错;
  3. 当 1 < k < len 的时候,k 最大为 len-1 的时候,fast 移动 len-1 步,直接到达尾结点,此时,snow 指向头结点。删除倒数第 k 个元素,即删除正数第 2 个结点即可;
  4. 当 k = len 的时候比较特殊,当 fast 移动 len 步的时候,已经指向了 fast.next = null,此时我们其实要删除的是头结点,直接返回 head.next 即可。

所以我们自然能得到这样的代码。

public class Test07 {    public static class LinkNode {        int data;        LinkNode next;        public LinkNode(int data) {            this.data = data;        }    }    private static LinkNode delTheSpecifiedReverse(LinkNode head, int k) {        LinkNode slow = head;        LinkNode fast = head;        if (fast == null) {            throw new RuntimeException("your linkNode is null");        }        // 先让 fast 先走 k 步        for (int i = 0; i < k; i++) {            if (fast == null) {                // 说明输入的 k 已经超过了链表长度,直接报错                throw new RuntimeException("the value k is too large.");            }            fast = fast.next;        }        // fast == null ,说明已经到了尾结点后面的空区域,说明要删除的就是头结点。        if (fast == null) {            return head.next;        }        while (fast.next != null) {            slow = slow.next;            fast = fast.next;        }        slow.next = slow.next.next;        return head;    }    public static void main(String[] args) {        LinkNode head = new LinkNode(1);        head.next = new LinkNode(2);        head.next.next = new LinkNode(3);        head.next.next.next = new LinkNode(4);        head.next.next.next.next = new LinkNode(5);        LinkNode node = delTheSpecifiedReverse(head, 3);        while (node != null) {            System.out.print(node.data + "->");            node = node.next;        }    }}

好了,我们解决了昨天文章中留下的拓展题,今天我们来看看我们链表都还有些怎样的考法。

面试题:定义一个单链表,输入一个链表的头结点,反转该链表并输出反转后链表的头结点。为了方便,我们链表的 data 采用整型。

这是一道反转链表的经典题,我们来屡一下思路:一个结点包含下一结点的引用,反转的意思就是要把原来指向下一结点的引用指向上一个结点。我们可以分为下面的步骤:

  1. 找到当前要反转的结点的下一个结点,并用变量保存,因为下一次要反转的是它,如果我们不保存的话一定会因为前面已经反转,导致无法通过遍历得到这个结点;
  2. 然后让当前结点的 next 引用指向上一个结点,上一个结点初始 null 因为头结点的反转后变成尾结点;
  3. 当前要反转的结点变成下一个要比较元素的上一个结点,用变量保存;
  4. 当前要比较的结点赋值为之前保存的未反转前的下一个结点;
  5. 当前反转的结点为 null 的时候,保存的上一个结点即反转后的链表头结点。

用代码实现就是:

public class Test08 {    private static class LinkNode {        int data;        LinkNode next;        LinkNode(int data) {            this.data = data;        }    }    private static LinkNode reverseLink(LinkNode head) {        // 上一个结点        LinkNode nodePre = null;        LinkNode next = null;        LinkNode node = head;        while (node != null) {            // 先用 next 保存下一个要反转的结点,不然会导致链表断裂。            next = node.next;            // 再把现在结点的 next 引用指向上一个结点            node.next = nodePre;            // 把当前结点赋值给 nodePre 变量,以便于下一次赋值            nodePre = node;            // 向后遍历            node = next;        }        return nodePre;    }    public static void main(String[] args) {        LinkNode head = new LinkNode(1);        head.next = new LinkNode(2);        head.next.next = new LinkNode(3);        head.next.next.next = new LinkNode(4);        head.next.next.next.next = new LinkNode(5);        LinkNode node = reverseLink(head);        while (node != null) {            System.out.print(node.data + "->");            node = node.next;        }    }}

链表可以考的可真多,相信不是小伙伴都和我一样,云里雾里了,那我们今天就讲到这里,后面还要继续考算法,你,打起精神,别睡着了。

转载地址:http://wlkix.baihongyu.com/

你可能感兴趣的文章
global_name启用以及修改规则
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
Spring Cache抽象详解
查看>>
微信JSSDK上传图片
查看>>
java集合类深入分析之Queue篇(1)
查看>>
bond的7种模式原理
查看>>
C语言的简单函数定义与调用
查看>>
二维码
查看>>
7-24
查看>>
spring中的JdbcTemplate简单记录
查看>>
pygame连载
查看>>
寒冰linux视频教程笔记12 计划任务
查看>>
在C盘上安装安装Windows Server 2008
查看>>
Servlet3.1 edr 规范中文版下载
查看>>
Magento支付宝插件V6.1旗舰版发布,支持即时到账、担保交易,新增订单重新支付功能!...
查看>>
基于Annotation方式的SpringMVC4+Spring4+Hibernate4
查看>>
我的友情链接
查看>>
git add 项目文件 改动
查看>>
GAP
查看>>