轻松搞定链表面试题

前言

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

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

    private static class Node {
        int value;
        Node next;

        Node(int value) {
            this.value = value;
        }
    }
    
    public static void main(String[] args) {
        Node head = init(1, 6);
//        Node head1 = init(8, 20);
//        display(head);
//        display(head);
        display(reverse(head));
//        display(mergeTwoSortList(head, head1));
//        display(removeInverseNode(head, 4));

    }
    
    public static void display(Node head) {
        Node p = head;
        while (p != null) {
            System.out.print(" " + p.value);
            p = p.next;
        }
        System.out.println();
    }
    
    public static Node init(int start, int exclusive) {
        // 设置一个哨兵节点
        Node head = new Node(-1);
        Node p = head;
        for (int i = start; i < exclusive; i++) {
            Node node = new Node(i);
            p.next = node;
            p = node;
        }
        return head.next;
    }
单链表逆序
 /**
     * 单链表逆序
     *
     * @param head
     */
  public Node reverse(Node head) {
        Node p = head;
        Node prev = null;
        while (p != null) {
            Node temp = p.next;
            p.next = prev;
            prev = p;
            p = temp;
        }
        return prev;
    }
合并两个有序链表
    // 合并两个有序链表
    public static Node mergeTwoSortList(Node head1, Node head2) {
        if (head1 == null) {
            return head2;
        }
        if (head2 == null) {
            return head1;
        }
        // 哨兵节点
        Node head = new Node(-1);
        Node p = head;
        Node h1 = head1;
        Node h2 = head2;
        while (h1 != null && h2 != null) {
            if (h1.value < h2.value) {
                p.next = h1;
                h1 = h1.next;
                p = p.next;
            } else {
                p.next = h2;
                h2 = h2.next;
                p = p.next;
            }
        }
        if (h1 != null) {
            p.next = h1;
        }
        if (h2 != null) {
            p.next = h2;
        }
        return head.next;
    } 
删除链表倒数第 n 个结点

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

 public static Node removeInverseNode(Node head, int n) {
        if (head == null || n < 1) {
            return null;
        }
        Node p = head;
        Node prev = head;
        // 先让 p 指针走 n 步
        int i = 0;
        while (i < n) {
            p = p.next;
            if (p == null) {
                // 到终点了
                break;
            }
            i++;
        }
        // 刚好走了 n - 1 步,说明链表只有 n 个节点
        if (i == n - 1) {
            // 删除第一个节点就好
            return head.next;
        }
        // n 大于链表长度的情况
        if (p == null) {
            return head;
        }
//        这个时候让 p 和 prev 一起走
        while (p.next != null) {
            p = p.next;
            prev = prev.next;
        }
        // p 和 prev 就是差 n 步的距离,这个时候 prev.next 正好是要被删除的节点
        prev.next = prev.next.next;
        return head;
    }
找出链表的中间结点

声明快慢指针,慢指针只遍历一个结点,快指针速度为 2 倍,当快指针指向链表最后一个结点,慢指针指向的即是链表的中间结点。

   public static Node findMiddleNode(Node head) {
        if (head == null) {
            return null;
        }
        Node prev = head;
        Node p = head;
        while (p != null && p.next != null) {
            p = p.next.next;
            prev = prev.next;
        }
        return prev;
    }

交换链表相邻元素
    public static void main(String[] args) {
        Node head1 = init(8, 20);
        display(swap(head1).next);
    }

    // 交换相邻链表元素值
    public static Node swap(Node head) {
        // 创建哨兵节点,使用哨兵节点节点会使解题容易,就不给自己找麻烦了
        Node node = new Node(0);
        node.next = head;
        head = node;
        // 初始化最初指针指向
        Node cur = node.next;
        Node prev = head;
        while (cur != null && cur.next != null) {
            // 标记除当前交换的两个节点的下一个节点
            Node next = cur.next.next;

            // 交换两个元素指针指向
            prev.next = cur.next;
            prev.next.next = cur;
            cur.next = next;

            // 重新调整指向开始下一轮循环
            prev = cur;
            cur = next;
        }
        return head;
    }

可参考:7把链表相邻元素翻转(交换值法、就地逆序)

链表中环的检测

参考:链表中环的检测

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值