关于链表的面试题

首先,定义链表的节点,以及链表打印函数。

class Node {
      public Integer value;
      public Node next;
}
public static void printList(Node head) {
        Node node = head;
        while (node != null) {
            System.out.println(node.value);
            node = node.next;
        }
    }

1. 在O(1)的时间删除单向链表节点    (《剑指offer》面试题13)

书中给出的方法是,O(1)的时间复杂度,将下一个节点的值复制到待删除的节点,然后直接删除下一个节点。

但是这种方法可能不合适,因为或许会有其他的指针指向下一个节点。

2. 两个单向链表的第一个公共节点    (《剑指offer》面试题37)

主要思路:由于链表是单向的,因此从第一个公共节点开始,后面的节点都是公共的。

分别遍历两个链表,得到其长度,并计算出长度差多少,然后长的链表先走这么几步。

3. 只遍历一遍,得到单向链表中倒数第k个节点    (《剑指offer》面试题15)

主要思路:两个指针,第一个指针先走k步,然后两个指针一起走,当前一个指针走到结尾的时候,后一个指针就到了倒数第k个节点。

注意边界情况,比如可能链表的长度小于k。

4. 合并两个排序的链表    (《剑指offer》面试题17)

其实就是归并排序中的归并操作。

以下代码,不改变输入参数,merge后的结果为一个新的链表。

public static Node merge(Node headA, Node headB) {
        if (headA == null && headB == null) return null;
        if (headA == null) return headB;    // 这里应该复制到一个新的链表,这里为省事,不写了
        if (headB == null) return headA;
        Node n1 = headA;
        Node n2 = headB;
        Node node = new Node();
        Node result = node;
        while (n1 != null || n2 != null) {
            if (n1 == null) {
                node.next = new Node(n2);
                n2 = n2.next;
                node = node.next;
                continue;
            }
            if (n2 == null) {
                node.next = new Node(n1);
                n1 = n1.next;
                node = node.next;
                continue;
            }
            if (n1.value < n2.value) {
                node.next = new Node(n1);
                n1 = n1.next;
            } else {
                node.next = new Node(n2);
                n2 = n2.next;
            }
            node = node.next;
        }
        return result.next;
    }

以上是迭代实现,也可以用递归。

5 反转链表    (《剑指offer》面试题16)

最容易的方法应该是用递归实现,如下:

 public static Node reverse(Node head) {
        if (head == null || head.next == null) return head;
        Node next = head.next;
        Node newHead = reverse(next);
        next.next = head;
        head.next = null;
        return newHead;
 }

改成迭代:

  public static Node reverse(Node head) {
        if (head == null || head.next == null) return head;
        Node prevNode = null;
        Node curNode = head;
        Node nextNode = curNode.next;
        while (nextNode != null) {
            curNode.next = prevNode;
            prevNode = curNode;
            curNode = nextNode;
            nextNode = nextNode.next;
        }
        curNode.next = prevNode;
        return curNode;
    }

总之,在写代码的时候,考虑问题要全面,并且处理好各种边界情况。

猜你喜欢

转载自blog.csdn.net/mrokayan/article/details/79846133