In the interview, I was asked about the reverse of the linked list, OMG~ Code it, Mark it! (Complete code including recursive implementation, non-recursive implementation, creating linked list, printing linked list, and test program—Java version)

broken thoughts

The reversal of the linked list can be described as a high-frequency question in the interview, and it is often asked. This topic will also appear in the interview or written test questions of large companies such as Microsoft, Facebook, Amazon, and Adobe. I was asked again today, OMG~ but I am not afraid. After reading today's article, I believe you can also write down this algorithm handsomely in front of the interviewer.

There are two ways to realize the inversion of linked list:

  • Idea 1: Traverse the linked list and change the pointers one by one.

    In terms of time, the entire linked list is only traversed once, so the time complexity is at the O(n) level;
    in terms of space, space for three pointers will be opened, so the space complexity is at the O(1) level.

  • Idea 2: Traverse the original linked list, put the elements in the stack one by one, and pop them out one by one. At this time, the linked list is traversed again, and the value of the linked list node is directly updated with the element popped from the top of the stack.

    It is inefficient and opens up additional space. Most importantly, it changes the value of the node in the linked list, and under normal circumstances, changing the value of the linked list is not allowed. So this idea is not advocated.

Let's introduce in detail how to achieve the reversal of the linked list handsomely.

The data structure of the linked list node

  • a data field
  • A next field pointing to the next node (can be understood as the next pointer in C++)
/**
 * 链表中的节点
 */
private static class ListNode {
    
    
    /**
     * 节点的值
     */
    private int val;

    /**
     * 节点的指针域,指向下一个节点
     */
    private ListNode next;

    /**
     * 构造函数
     *
     * @param value
     */
    public ListNode(int value) {
    
    
        val = value;
    }
}

Linked list reversal implementation

non-recursive

insert image description here
Complexity Analysis

  • Only traverse the entire linked list once, and the time complexity is O(n) level
  • In terms of space complexity, because the space for three pointers is opened, it is O(1)
/**
 * 实现链表反转(非递归方式 - 修改指针)
 * 时间复杂度:O(n)
 * 空间复杂度:O(1)
 *
 * @param head
 * @return
 */
public static ListNode reverse(ListNode head) {
    
    

    ListNode cur = head;

    ListNode pre = null;

    while (cur != null) {
    
    
        // 保存next指针,指向当前节点的下一个节点
        ListNode next = cur.next;

        // 当前节点指针反转,指向它的前一个节点
        cur.next = pre;

        // pre指向cur
        pre = cur;

        // cur指向next
        cur = next;
    }

    return pre;
}

recursion

Recursion is an elegant way of writing~

/**
* 实现链表反转(递归方式)
 *
 * @param node
 * @return
 */
public static ListNode reverseRecursion(ListNode node) {
    
    
    if (node.next == null || node == null) {
    
    
        return node;
    }
    ListNode tempNode = reverse(node.next);
    node.next.next = node;
    node.next = null;
    return tempNode;
}

Linked list creation

non-recursive

/**
 * 通过数组创建链表(非递归方式)
 *
 * @param arr
 * @return
 */
public static ListNode createLinkedList(int[] arr) {
    
    

    if (null == arr || arr.length == 0) {
    
    
        return null;
    }

    // 创建头节点
    ListNode head = new ListNode(arr[0]);

    // 当前节点curNode指向head
    ListNode curNode = head;

    for (int i = 1; i < arr.length; i++) {
    
    
        // 当前节点的next域指向新创建的节点
        curNode.next = new ListNode(arr[i]);

        // 当前节点向后移
        curNode = curNode.next;
    }

    // 返回链表的头节点
    return head;
}

recursion

/**
 * 通过数组创建链表(递归方式)
 *
 * @param arr
 * @return
 */
public static ListNode createLinkedListRecursion(int[] arr) {
    
    
    if (null == arr || arr.length == 0) {
    
    
        return null;
    }

    ListNode head = new ListNode(arr[0]);
    ListNode tempNode = createLinkedList(ArrayUtil.sub(arr, 1, arr.length));
    head.next = tempNode;

    // 返回链表的头节点
    return head;
}

Tips:
For the interception of the array, the ArrayUtil tool class is used here, which is a tool class in hutool. hutool is a small and complete Java class library, homophonic for "confused", but it is not confused at all when used. It can be said that the Java language can also be sweet (so cold~ but it is true). If you are interested, you can use it. If it is a Maven program, you can directly add this dependency in the pom file.

<dependency>
    <groupId>cn.hutool</groupId>
    <artifactId>hutool-all</artifactId>
    <version>5.3.1</version>
</dependency>

Linked list printing

/**
 * 打印链表
 *
 * @param head
 */
public static void printLinkedList(ListNode head) {
    
    

    ListNode curNode = head;

    while (curNode != null) {
    
    
        // 打印当前节点
        System.out.print(curNode.val + " -> ");

        // 当前节点向后移
        curNode = curNode.next;
    }
    System.out.println("NULL");
}

full code

package basic.linkedlist;

import cn.hutool.core.util.ArrayUtil;

/**
 * @Description:链表反转
 * @Author: during
 * @Date: 2020/4/21
 */
public class ReverseLinkedList {
    
    

    /**
     * 链表中的节点
     */
    private static class ListNode {
    
    
        /**
         * 节点的值
         */
        private int val;

        /**
         * 节点的指针域,指向下一个节点
         */
        private ListNode next;

        /**
         * 构造函数
         *
         * @param value
         */
        public ListNode(int value) {
    
    
            val = value;
        }
    }

    /**
     * 通过数组创建链表(非递归方式)
     *
     * @param arr
     * @return
     */
    public static ListNode createLinkedList(int[] arr) {
    
    

        if (null == arr || arr.length == 0) {
    
    
            return null;
        }

        // 创建头节点
        ListNode head = new ListNode(arr[0]);

        // 当前节点curNode指向head
        ListNode curNode = head;

        for (int i = 1; i < arr.length; i++) {
    
    
            // 当前节点的next域指向新创建的节点
            curNode.next = new ListNode(arr[i]);

            // 当前节点向后移
            curNode = curNode.next;
        }

        // 返回链表的头节点
        return head;
    }

    /**
     * 通过数组创建链表(递归方式)
     *
     * @param arr
     * @return
     */
    public static ListNode createLinkedListRecursion(int[] arr) {
    
    
        if (null == arr || arr.length == 0) {
    
    
            return null;
        }

        ListNode head = new ListNode(arr[0]);
        ListNode tempNode = createLinkedList(ArrayUtil.sub(arr, 1, arr.length));
        head.next = tempNode;

        // 返回链表的头节点
        return head;
    }

    /**
     * 打印链表
     *
     * @param head
     */
    public static void printLinkedList(ListNode head) {
    
    

        ListNode curNode = head;

        while (curNode != null) {
    
    
            // 打印当前节点
            System.out.print(curNode.val + " -> ");

            // 当前节点向后移
            curNode = curNode.next;
        }
        System.out.println("NULL");

    }

    /**
     * 实现链表反转(非递归方式 - 修改指针)
     * 时间复杂度:O(n)
     * 空间复杂度:O(1)
     *
     * @param head
     * @return
     */
    public static ListNode reverse(ListNode head) {
    
    

        ListNode cur = head;

        ListNode pre = null;

        while (cur != null) {
    
    
            // 保存next指针,为当前节点的next域
            ListNode next = cur.next;

            // 当前节点指针反转,指向它的前一个节点
            cur.next = pre;

            // pre指向cur
            pre = cur;

            // cur指向next
            cur = next;
        }

        return pre;
    }

    /**
     * 实现链表反转(递归方式)
     *
     * @param node
     * @return
     */
    public static ListNode reverseRecursion(ListNode node) {
    
    
        if (node.next == null || node == null) {
    
    
            return node;
        }
        ListNode tempNode = reverse(node.next);
        node.next.next = node;
        node.next = null;
        return tempNode;
    }

    /**
     * 测试
     *
     * @param args
     */
    public static void main(String[] args) {
    
    
        int count = 100;
        int[] arr = new int[count];
        for(int i = 0; i< count; i++) {
    
    
            arr[i] = i;
        }

        ListNode head = createLinkedList(arr);
        /*ListNode head = createLinkedListRecursion(arr);*/
        printLinkedList(head);

        ListNode reverseHead = reverse(head);
        /*ListNode reverseHead = reverseRecursion(head);*/
        printLinkedList(reverseHead);
    }
}

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.during</groupId>
    <artifactId>algorithm</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.3.1</version>
        </dependency>
    </dependencies>

</project>

Guess you like

Origin blog.csdn.net/u011886447/article/details/105656525