题解 | #链表内指定区间反转#

链表内指定区间反转

https://www.nowcoder.com/practice/b58434e200a648c589ca2063f1faf58c

import java.util.*;
/**
     * 本题的输入是一个listnode,和拆分的两个数字,通过两个数字把listnode进行切割成三段。
     * 解题过程将listnode看成一个数组,并进行遍历,
     * 通过两个数字对数据切割成三段,不管其中是否有数据,都切割成三段。
     * 将三段数据在拼接成一个listnode进行返回。
     * 注意:遍历原始listnode时,需要使用的是遍历后剩余节点的数据。
     */
/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 反转链表中指定范围的节点。
     *
     * @param head 链表的头节点。
     * @param m 范围开始的节点索引(包含)。
     * @param n 范围结束的节点索引(包含)。
     * @return 反转指定范围后的链表头节点。
     */
    public static ListNode reverseBetween(ListNode head, int m, int n) {
        // 如果链表为空或只有一个节点,直接返回原链表
        if (head == null || head.next == null) {
            return head;
        }
        // 左侧链表第一个节点
        ListNode left = new ListNode(-1);
        // 创建虚拟节点用于分割链表-左边部分
        ListNode head1 = splitListNode(left, head, m);
        // 获取分割后的左侧链表头节点
        left = deleteFirstNode(left);

        // 中间侧链表第一个节点
        ListNode middle = new ListNode(-1);
        // 分割并获取要反转的中间部分链表
        // 分割并获取要反转的中间部分链表
        int num = 0;
        if (n - m <= 0) {
            num = 0;
        } else {
            num = n - m + 2;
        }
        ListNode head2 = splitListNode(middle, head1, num);
        // 获取中间部分链表
        middle = deleteFirstNode(middle);

        // 右侧链表第一个节点
        ListNode right = new ListNode(-1);
        // 分割并获取右侧链表
        ListNode head3 = splitListNode(right, head2, Integer.MAX_VALUE);
        // 获取右侧链表头节点,并删除第一个节点
        print(left);
        print(middle);
        print(right);
        right = deleteFirstNode(right);

        // 反转中间部分链表,并合并到左侧链表
        ListNode leftMerge = mergeTwoLists(left, reverseList(middle));
        // 将左侧链表、反转后的中间部分链表和右侧链表合并
        ListNode rightMerge = mergeTwoLists(leftMerge, right);
        // 返回合并后的链表头节点
        return rightMerge;
    }

    /**
    * 打印链表中所有节点的值。
    * @param p 链表的头节点。类型为ListNode,表示一个链表的节点。
    * 该函数没有返回值。
    */
    private static void print(ListNode p) {
        // 遍历链表,打印每个节点的值
        while (p != null) {
            System.out.println(p.val);
            p = p.next;
        }
        // 打印分隔线,以区分不同的链表打印输出
        System.out.println("------------------------");
    }

    /**
     * 反转链表。
     *
     * @param head 链表的头节点。
     * @return 反转后的链表的头节点。
     */
    public static ListNode reverseList(ListNode head) {
        // 如果链表为空或只有一个节点,直接返回头节点
        if (head == null || head.next == null) {
            return head;
        }
        ListNode temp = head.next; // 要反转的节点,从第二个节点开始
        ListNode nextNode = temp.next; // 要反转的节点的下一个节点
        head.next =
            null; // 断开头节点和要反转节点的连接,防止反转后形成环

        // 使用头插法反转链表
        while (temp != null) {
            temp.next = head;
            head = temp;
            temp = nextNode;
            if (nextNode != null) {
                nextNode = nextNode.next;
            }
        }
        return head; // 返回反转后的链表的头节点
    }

    /**
     * 删除链表的第一个节点。
     * 该方法接收一个链表的头节点,并删除该链表的第一个节点,然后返回链表的新头节点。
     *
     * @param listNode 链表的头节点。如果链表为空,则不进行任何操作并返回null。
     * @return 返回删除第一个节点后的链表的头节点。如果原链表为空,则返回null。
     */
    private static ListNode deleteFirstNode(ListNode listNode) {
        // 检查链表是否为空
        if (listNode != null) {
            // 新的头节点指向原头节点的下一个节点
            ListNode newNode = listNode.next;
            listNode.next =
                null; // 删除原链表的第一个节点,将头节点的next指针置为null
            listNode = newNode; // 更新头节点为新的头节点
        }
        return listNode; // 返回新的头节点
    }

    public static ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        //任意一跳链表为空时,直接返回另外一条链表
        if (list1 == null) {
            return list2;
        } else if (list2 == null) {
            return list1;
        } else {
            //当前层数的返回结果,放在list1后面
            list1.next = mergeTwoLists(list1.next, list2);
            return list1;
        }
    }

    /**
     * 根据 n的值对listnode进行切割,切割时listnode的值是按照当前node的节点进行切割,也就是0到n为一组.
     * 比如head原始数据=0-1-2-3-4-5-6,当前指针的节点为2,那就是2之后的n个元素为返回值。
     *
     * @param head head,遍历的listnode
     * @param n    n个数
     * @return ListNode
     */
    private static ListNode splitListNode(ListNode node, ListNode head, int n) {
        ListNode currentNode = node;
        // 遍历链表,找到拆分点
        for (int i = 1; i < n; i++) {
            // 如果head为null,说明给定的n超出了链表的长度,直接退出循环
            if (head == null) {
                break;
            }
            currentNode.next = head;
            currentNode = head;
            // 移动到下一个节点
            head = head.next;
        }
        // 断开链表,形成两个独立的部分
        currentNode.next = null;
        // 返回被拆分出来的后半部分链表的头节点
        return head;
    }
}

全部评论

相关推荐

希望被捞的猫头鹰很理智:大概率待遇低怕硕士跑路
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务