轻松搞定链表面试题

前言

检查链表代码是否正确的边界条件:

  1. 若链表为 null,代码是否正常运行?
  2. 若链表只有一个结点,代码是否正常运行?
  3. 若链表只有两个结点,代码是否正常运行?
  4. 代码逻辑在处理头结点和尾结点的时候,代码是否正常运行?

链表的构造及打印

  public static void main(String[] args) {
    
    
        int[] arr = {
    
    1, 3, 5, 7, 9, 11, 13, 15, 17};
        LinkedListDemo linkedListDemo = new LinkedListDemo();
        Node head1 = linkedListDemo.buildLinkedList(arr);
        linkedListDemo.display(head1);
        // 链表逆序
        linkedListDemo.display(linkedListDemo.reverseList(head1));
        linkedListDemo.display(head1);
    }

    private static class Node {
    
    
        final Integer item;
        Node next;

        Node(Integer item, Node next) {
    
    
            this.item = item;
            this.next = next;
        }
    }
    
    /**
     * 打印链表
     *
     * @param header
     */
    public void display(Node header) {
    
    
        Node p = header;
        while (p != null) {
    
    
            System.out.print(p.item + " ");
            p = p.next;
        }
        System.out.println();
    }

    /**
     * 通过数组构造一个链表
     *
     * @param arr
     * @return
     */
    public Node buildLinkedList(int[] arr) {
    
    
        if (Objects.isNull(arr) || arr.length < 1) {
    
    
            throw new IllegalArgumentException("illegal arr");
        }
        Node head = new Node(arr[0], null);
        if (arr.length >= 2) {
    
    
            Node p = head;
            for (int i = 1; i < arr.length; i++) {
    
    
                Node temp = new Node(arr[i], null);
                p.next = temp;
                p = temp;
            }
        }
        return head;
    }

    public void checkNull(Node head) {
    
    
        if (head == null) {
    
    
            throw new NullPointerException();
        }
    }

单链表逆序

 /**
     * 单链表逆序
     *
     * @param head
     */
    public Node reverseList(Node head) {
    
    
        this.checkNull(head);
        Node p = head.next;
        head.next = null;
        Node temp;
        while (p != null) {
    
    
            temp = p.next;
            p.next = head;
            head = p;
            p = temp;
        }
        return head;
    }

合并两个有序链表

 /**
     * 合并两个有序链表
     *
     * @param head1
     * @param head2
     * @return
     */
    public Node mergeTwoSortedLinkedList(Node head1, Node head2) {
    
    
        if (head1 == null && head2 == null) {
    
    
            throw new IllegalArgumentException("Illegal params");
        }
        if (head1 == null) {
    
    
            return head2;
        }

        if (head2 == null) {
    
    
            return head1;
        }
        // 设置一个哨兵结点
        Node head = new Node(null, null);
        Node p = head;
        while (head1 != null && head2 != null) {
    
    
            if (head1.item < head2.item) {
    
    
                p.next = head1;
                p = head1;
                head1 = head1.next;
            } else {
    
    
                p.next = head2;
                p = head2;
                head2 = head2.next;
            }
        }

        // 拼接链表的剩下部分
        if (head1 != null) {
    
    
            p.next = head1;
        }

        if (head2 != null) {
    
    
            p.next = head2;
        }

        p = null;
        return head.next;
    }

删除链表倒数第 n 个结点

声明快慢两个指针,让快指针走 n 步,再让两个指针同时后移,直到快指针到指向最后一个结点时,慢指针的下一个结点就是要删除的结点。

  /**
     * 删除链表倒数第 n 个结点
     *
     * @param head
     * @param n
     * @return
     */
    public Node removeNode(Node head, Integer n) {
    
    
        if (head == null) {
    
    
            return null;
        }
        Node slow = head, fast = head;
        // 让快指针先走 n 步
        int i = 0;
        while (fast != null && i < n) {
    
    
            fast = fast.next;
            i++;
        }
        // 如果指定的 n 大于链表的长度,不进行删除处理
        if (n > i) {
    
    
            return head;
        }

        //如果指定的 n 等于链表的长度,删除第一个结点
        if (fast == null) {
    
    
            return head.next;
        }
        // 同时移动两个指针直到快指针指向尾结点
        while (fast.next != null) {
    
    
            slow = slow.next;
            fast = fast.next;
        }
        // 删除 slow.next
        slow.next = slow.next.next;
        return head;
    }

找出链表的中间结点

声明快慢指针,慢指针只遍历一个结点,快指针速度为 2 倍,当快指针指向链表最后一个结点(链表总结点数是奇数)或快指针指向倒数第二个结点(链表总结点数是偶数)时,慢指针指向的即是链表的中间结点。

    /**
     * 找出链表的中间结点
     *
     * @param head
     * @return
     */
    public Node getMiddleNode(Node head) {
    
    
        this.checkNull(head);
        Node fast = head, slow = head;
        while (fast != null && fast.next != null && fast.next.next != null) {
    
    
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;
    }

链表中环的检测

参考:链表中环的检测

猜你喜欢

转载自blog.csdn.net/jiaobuchong/article/details/84675815