【leetcode】LCR 123. 图书整理 I(简单)题解学习

题目描述:

书店店员有一张链表形式的书单,每个节点代表一本书,节点中的值表示书的编号。为更方便整理书架,店员需要将书单倒过来排列,就可以从最后一本书开始整理,逐一将书放回到书架上。请倒序返回这个书单链表。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public int[] reverseBookList(ListNode head) {

    }
}

示例 1:

输入:head = [3,6,4,1]

输出:[1,4,6,3]

提示:

0 <= 链表长度 <= 10000

代码实现:

方法一:

要将书单链表反转,我们可以使用迭代或递归的方法。将给定的单链表反转,并将反转后的结果存储在一个数组中返回。以下是一种可能的实现:

class Solution {
    public int[] reverseBookList(ListNode head) {
        // 计算链表长度
        int len = 0;
        ListNode curr = head;
        while (curr != null) {
            len++;
            curr = curr.next;
        }

        // 将链表反转
        ListNode prev = null;
        curr = head;
        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
        }

        // 将反转后的链表节点值存储到数组中
        int[] result = new int[len];
        int i = 0;
        curr = prev;
        while (curr != null) {
            result[i++] = curr.val;
            curr = curr.next;
        }

        return result;
    }
}

在上述代码中,我们首先计算出原始链表的长度 len,然后利用迭代的方式将链表反转,并将反转后的节点值存储到数组中,最后返回该数组即可。

需要注意的是,当链表为空或只有一个节点时,反转链表不需要进行任何操作,直接返回原始链表即可。

同时,也需要注意代码的鲁棒性,即对于空链表或空数组,需要进行特殊处理,保证程序正确运行。

在上述方法中,我们首先遍历链表来计算长度,然后再进行反转操作。这个过程需要两次遍历链表,因此可以考虑优化性能,只进行一次遍历。

以下是一种只进行一次遍历的优化方法:

class Solution {
    public int[] reverseBookList(ListNode head) {
        // 处理空链表情况
        if (head == null) {
            return new int[0];
        }

        ListNode prev = null;
        ListNode curr = head;
        int len = 0;

        while (curr != null) {
            ListNode nextTemp = curr.next;
            curr.next = prev;
            prev = curr;
            curr = nextTemp;
            len++;
        }

        // 将反转后的链表节点值存储到数组中
        int[] result = new int[len];
        int i = 0;
        while (prev != null) {
            result[i++] = prev.val;
            prev = prev.next;
        }

        return result;
    }
}

在这个优化的方法中,我们先处理空链表的情况,如果链表为空,则直接返回一个空数组。然后我们使用一个变量 len 记录链表的长度,同时在进行链表反转的同时,将节点值存储到数组中,最后返回该数组。

这个优化方法只需要一次遍历就可以完成链表反转和数组构建,相比于之前的方法减少了一次遍历,因此可以提升性能。

方法二:

使用栈和数组的方式:

import java.util.Stack;

class Solution {
    public int[] reverseBookList(ListNode head) {
        // 处理空链表情况
        if (head == null) {
            return new int[0];
        }
        
        Stack stack = new Stack<>();
        ListNode curr = head;

        while (curr != null) {
            stack.push(curr.val);
            curr = curr.next;
        }

        int[] result = new int[stack.size()];
        int i = 0;

        while (!stack.isEmpty()) {
            result[i++] = stack.pop();
        }

        return result;
    }
}

在这个方法中,我们使用一个栈来存储链表节点值。首先,遍历链表,将节点值依次入栈。然后,创建一个新的数组,长度为栈的大小,依次将栈中的元素出栈并存储到数组中。

这种方法的时间复杂度为 O(n),其中 n 是链表的长度。因为需要遍历链表一次来入栈,然后再遍历栈一次来构建数组。

注意,在这种方法中,由于使用了额外的栈来存储链表节点值,因此会占用额外的空间。如果空间复杂度是一个关注点,那么迭代或递归的方法可能更适合。

以上使用递归和栈辅助的两种方法的时间和空间复杂度都是 O(N)。

对于使用递归的方法,在每一次递归调用中,都会向链表的尾部逐步递进,因此时间复杂度为 O(N),其中 N 是链表的长度。另外,由于递归调用的层数不超过链表的长度,因此递归方法的空间复杂度也是 O(N)。

对于使用栈辅助的方法,在遍历链表时,需要将每个节点的值存储到栈中,因此空间复杂度为 O(N)。另外,在遍历栈并构建反转后的链表时,需要遍历整个栈,时间复杂度也是 O(N)。

你可能感兴趣的:(leetcode,数据结构,算法,leetcode,学习,算法,java)