6.查找单链表中的倒数第k个结点
普通思路:先将整个链表从头到尾遍历一次,计算出链表的长度size,得到链表的长度之后,就好办了,直接输出第(size-k)个节点就可以了(注意链表为空,k
为0,k为1,k大于链表中节点个数时的情况)。时间复杂度为O(n),大概思路如下:
public int findLastNode(int index) { // index代表的是倒数第index的那个结点 // 第一次遍历,得到链表的长度size if (head == null) { return -1; } int size = 0; current = head; while (current != null) { size++; current = current.next; } // 第二次遍历,输出倒数第index个结点的数据 current = head; for (int i = 0; i < size - index; i++) { current = current.next; } return current.data; }
如果面试官不允许你遍历链表的长度,该怎么做呢?接下来就是。
改进思路:(这种思路在其他题目中也有应用)
这里需要声明两个指针:即两个结点型的变量first和second,首先让first和second都指向第一个结点,然后让second结点往后挪k-1个位置,此时first和second就间隔了k-1个位置,然后整体向后移动这两个节点,直到second节点走到最后一个结点的时候,此时first节点所指向的位置就是倒数第k个节点的位置。时间复杂度为O(n)
代码实现:(初版)
public Node findLastNode(Node head, int index) { if (head == null) { return null; } Node first = head; Node second = head; // 让second结点往后挪index个位置 for (int i = 0; i < index; i++) { second = second.next; } // 让first和second结点整体向后移动,直到second结点为Null while (second != null) { first = first.next; second = second.next; } // 当second结点为空的时候,此时first指向的结点就是我们要找的结点 return first; }
代码实现:(最终版)
(考虑k大于链表中结点个数时的情况时,抛出异常)
上面的代码中,看似已经实现了功能,其实还不够健壮:
要注意k等于0的情况;
如果k大于链表中节点个数时,就会报空指针异常,所以这里需要做一下判断。
核心代码如下:
public Node findLastNode(Node head, int k) { if (k == 0 || head == null) { return null; } Node first = head; Node second = head; // 让second结点往后挪k-1个位置 for (int i = 0; i < k - 1; i++) { System.out.println("i的值是" + i); second = second.next; if (second == null) { // 说明k的值已经大于链表的长度了 //throw new NullPointerException("链表的长度小于" + k); //我们自己抛出异常,给用户以提示 return null; } } // 让first和second结点整体向后移动,直到second走到最后一个结点 while (second.next != null) { first = first.next; second = second.next; } // 当second结点走到最后一个节点的时候,此时first指向的结点就是我们要找的结点 return first; }
测试代码:
public static void main(String[] args) { LinkList list = new LinkList(); // 向LinkList中添加数据 for (int i = 0; i < 10; i++) { list.add(i); } list.print(list.head);// 从head节点开始遍历输出 System.out.print(list.getLength(list.head)); System.out.print("\r\n"); // System.out.print(list.findLastNode(10)); System.out.print(list.findLastNode(list.head,7).getData()); System.out.print("\r\n"); System.out.print(list.findMidNode(list.head).data); }