昨天在最后给你们留了拓展题,不知道你们有没有思考完成,其实南尘说有巨坑是吓你们的啦,实际上也没什么。咱们来继续看看昨天这个拓展题。java
面试题:给定单链表的头结点,删除单链表的倒数第 k 个结点。node
前面的文章见连接:面试 7:面试常见的链表算法捷径(一)面试
这个题和前面的文章中增长了一个操做,除了找出来这个结点,咱们还要删除它。删除一个结点,想必你们一定也知道:要想操做(添加、删除)单链表的某个结点,那咱们还得知道这个节点的前一个节点。因此咱们要删除倒数第 k 个结点,就必需要找到倒数第 k+1 个结点。而后把倒数第 k+1 个元素的 next 变量 p.next 指向 p.next.next。算法
咱们找到倒数第 k 个结点的时候,先让 fast 走了 k-1 步,而后再让 slow 变量和 fast 同步走,它们之间就会一直保持 k-1 的距离,因此当 fast 到链表尾结点的时候,slow 刚刚指向的是倒数第 k 个结点。this
本题因为咱们要知道倒数第 k+1 个结点,因此得让 fast 先走 k 步,待 fast 指向链表尾结点的时候,slow 正好指向倒数第 k+1 个结点。spa
咱们简单思考一下临界值:code
因此咱们天然能获得这样的代码。ci
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 采用整型。string
这是一道反转链表的经典题,咱们来屡一下思路:一个结点包含下一结点的引用,反转的意思就是要把原来指向下一结点的引用指向上一个结点。咱们能够分为下面的步骤:
用代码实现就是:
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; } } }
链表能够考的可真多,相信不是小伙伴都和我同样,云里雾里了,那咱们今天就讲到这里,后面还要继续考算法,你,打起精神,别睡着了。