Java算法面试题(002) 如何通过一次迭代找到LinkedList的中间元素

来源:互联网 发布:linux修改nice值 编辑:程序博客网 时间:2024/06/06 15:17

声明:本文为本博主翻译,未经允许,严禁转载!

简介

Java和非Java程序员在电话面试中经常被问及如何仅一次遍历查找到LinkedList的中间元素。这个问题类似于检查回文或者计算阶乘,面试官有时也会要求编写代码。为了回答这个问题,候选人必须熟悉LinkedList数据结构,即在单LinkedList的情况下,链表的每个节点都包含数据和指针,它是下一个链表节点的地址,单链表的最后一个元素指向null。由于为了找到链表的中间元素,你需要找到LinkedList的长度,这需要对链表节点进行计数直到最后一个元素为止。让这个数据结构面试问题有趣的是,你需要在一次遍历中找到LinkedList的中间元素,而你不知道LinkedList的长度。这是考验候选人逻辑能力的地方:他是否熟悉空间和时间的权衡等等。
 
如果你仔细想想,你可以通过使用两个指针来解决这个问题,就像我在上一篇关于如何在Java中查找单一链表的长度的文章中提到的那样。通过使用两个指针,其中一个每次迭代增一,另外一个每两次迭代增。当第一个指针指向链表的末尾时,第二个指针将指向链表的中间节点。

实际上,这两个指针方法可以解决多个相似的问题,如何在一个迭代中从链表中找到倒数第3个元素,或者如何在链表中找到倒数第N个元素。在这个Java编程教程中,我们将看到一个Java程序,它在一个迭代中查找链接列表的中间元素。


这里是完整的Java程序来查找Java中的链表的中间节点。记住LinkedList类是我们的自定义类,不要把这个类与Java中流行的Collection类java.util.LinkedList混淆。在这个Java程序中,我们的类LinkedList表示一个包含节点集合并具有头部和尾部的链表数据结构。每个节点都包含数据和地址部分。 LinkedListTest类的主要方法是用来模拟问题的,在这里我们创建了Linked List,并在其上添加了一些元素,然后遍历它们在Java中一次遍历链接列表的中间元素。

通过一次LinkedList迭代查找中间元素的Java程序

/** * Java program to find middle element of linked list in one pass. In order to * find middle element of linked list we need to find length first but since we * can only traverse linked list one time, we will use two pointers one which we * will increment on each iteration while other which will be incremented every * second iteration. so when first pointer will point to the end of linked list, * second will be pointing to the middle element of linked list *  * @author */public class LinkedListTest {public static void main(String[] args) {// creating LinkedList with 5 elements including headLinkedList list = new LinkedList();list.add(new LinkedList.Node("1"));list.add(new LinkedList.Node("2"));list.add(new LinkedList.Node("3"));list.add(new LinkedList.Node("4"));list.add(new LinkedList.Node("5"));LinkedList.Node head = list.head();// finding middle element of LinkedList in a single passLinkedList.Node current = head;LinkedList.Node middle = head;int length = 0;while (current.next() != null) {length++;if (length % 2 == 0) {middle = middle.next();}current = current.next();}length++;System.out.println("length of LinkedList: " + length);System.out.println("middle element of LinkedList : " + middle);}}class LinkedList {private Node head;private Node tail;/** * Constructs an empty list */public LinkedList() {head = null;tail = null;}public Node head() {return head;}public void add(Node node) {if (head == null) {head = node;tail = node;return;}tail.next = node;tail = node;}public static class Node {private Node next;private String data;public Node(String data) {this.data = data;}public String data() {return data;}public void setData(String data) {this.data = data;}public Node next() {return next;}public void setNext(Node next) {this.next = next;}public String toString() {return this.data;}}}

原文链接

How to find middle element of LinkedList in Java in one pass in Java

译者备注

1. 译文中实现与原实现有些差异,原文中在链表初始化时自动创建了一个无关节点,相关实现也不容易理解,这块在上文中译者进行了优化,感兴趣的可以对比一下原文的实现。

2. 你应该搞清楚迭代一次是什么意思。如果面试官说你不能循环两次而只需要使用一个循环,那么你可以使用两个指针来解决这个问题。在两个指针方法中,你有两个指针,快指针和慢指针。在每个步骤中,快速指针移动两个节点,而慢速指针仅移动一个节点。所以,当快速指针指向最后一个节点,即下一个节点为空时,慢速指针将指向链表的中间节点。

3. 这里再举一个类似的案例,可以使用本文的算法解决: 例如,假设你有一个链表a1  - > a2  - > ...  - > an  - > b1  - > b2  - > ...  - > bn,将其重新排列为a1→b1→a2→b2→b→a→bn。你不知道链表的长度(但是你要知道长度是偶数)。你可以有一个指针p1(快速指针)为每次移动两个元素,而p2(慢速指针)每次移动一个元素。当p1到达链表的末尾时,p2将处于中点。然后,将p1移回前面并开始组织的元素。在每次迭代中,p2选择一个元素并将其插入到p1之后。

阅读全文
0 0
原创粉丝点击