Java关于重排链表详细解析

Java关于重排链表详细解析

问题描述

给定一个单链表 L 的头节点 head ,单链表 L 表示为:

L0 -> L1 -> L2 -> ... -> Ln-1 -> Ln

需要将单链表 L 进行重新排列,使得新的链表既符合以下格式,也保留原链表元素的相对顺序:

L0 -> Ln -> L1 -> Ln-1 -> L2 -> Ln-2 -> ...

例如,将单链表 L = 1 -> 2 -> 3 -> 4 -> 5 -> 6 进行重排后,新链表应为 1 -> 6 -> 2 -> 5 -> 3 -> 4 。

解题思路

初步看到这道题目,我们很容易想到的是:将单链表拆成前半段与后半段,然后将后半段翻转,最后将前半段与后半段交叉拼接。

将单链表拆成前半段与后半段

首先,我们需要找到单链表 L 的中间节点,可以使用快慢指针的方法,一个指针每次向后移动 1 个节点,另一个指针每次向后移动 2 个节点,当快指针到达链表末尾时,慢指针恰好到达中间位置,这样便可以将单链表拆分成前半段与后半段。

int length = 0;
ListNode node = head;
while (node != null) {
    length++;
    node = node.next;
}

ListNode node1 = head;
ListNode node2 = null;

for (int i = 0; i < (length + 1) / 2; i++) {
    node2 = node1;
    node1 = node1.next;
}

node2.next = null; // 将链表断成两半

翻转后半段链表

接下来,我们需要对后半段链表进行翻转。这个问题不难,只需要使用三个指针,分别指向当前节点、前驱节点和后继节点,然后对当前节点的 next 指针进行反转即可。

/**
 * 翻转链表
 * @param head
 */
public void reverseList(ListNode head) {
    ListNode pre = null;
    ListNode cur = head;
    ListNode next = null;

    while (cur != null) {
        next = cur.next;
        cur.next = pre;
        pre = cur;
        cur = next;
    }
}

交叉拼接前半和后半段链表

最后,我们将前半段与翻转后的后半段依次交叉拼接即可。

ListNode cur1 = head;
ListNode cur2 = newHead;
ListNode next1 = null;
ListNode next2 = null;

while (cur2 != null) {
    next1 = cur1.next;
    next2 = cur2.next;

    cur1.next = cur2;
    cur2.next = next1;

    cur1 = next1;
    cur2 = next2;
}

完整代码:

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public void reorderList(ListNode head) {
        if (head == null || head.next == null) {
            return;
        }

        // 将链表断成两半
        int length = 0;
        ListNode node = head;
        while (node != null) {
            length++;
            node = node.next;
        }

        ListNode node1 = head;
        ListNode node2 = null;

        for (int i = 0; i < (length + 1) / 2; i++) {
            node2 = node1;
            node1 = node1.next;
        }

        node2.next = null;

        // 翻转链表
        ListNode pre = null;
        ListNode cur = node1;
        ListNode next = null;

        while (cur != null) {
            next = cur.next;
            cur.next = pre;
            pre = cur;
            cur = next;
        }

        ListNode newHead = pre;

        // 交叉拼接前半和后半段链表
        ListNode cur1 = head;
        ListNode cur2 = newHead;
        ListNode next1 = null;
        ListNode next2 = null;

        while (cur2 != null) {
            next1 = cur1.next;
            next2 = cur2.next;

            cur1.next = cur2;
            cur2.next = next1;

            cur1 = next1;
            cur2 = next2;
        }
    }
}

示例说明

示例 1

单链表 L = 1 -> 2 -> 3 -> 4 -> 5 -> 6

中间节点为 3 ,将单链表拆分成前半段 1 -> 2 -> 3 和后半段 4 -> 5 -> 6

翻转后半段链表,得到 6 -> 5 -> 4

交叉拼接前半段和后半段链表,得到 1 -> 6 -> 2 -> 5 -> 3 -> 4

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java关于重排链表详细解析 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • Android Activity生命周期调用的理解

    Android Activity生命周期调用是我们在开发Android应用时必须要理解的重要概念。下面,我将会详细讲解关于Android Activity生命周期调用的攻略。 什么是Android Activity生命周期 Android Activity生命周期指的是一个应用中Activity从创建到销毁的整个过程。在这个过程中每个状态都有相应的方法或回调…

    other 2023年6月27日
    00
  • jenkins运行python脚本

    Jenkins运行Python脚本 Jenkins是一款流行的持续集成和持续部署工具,可以自动构建、测试和部署你的应用程序。它支持多种编程语言和技术,并且扩展性非常强,可以通过插件来适应不同的场景和需求。在本文中,我们将介绍如何使用Jenkins来运行Python脚本。 准备工作 在开始之前,需要准备以下工具和环境: 安装Jenkins服务器; 安装Pyth…

    其他 2023年3月28日
    00
  • win7系统桌面上和开始菜单中的图标都变成了word文件后缀为.lnk

    攻略:修复Win7系统桌面和开始菜单中的图标变成.lnk文件后缀 步骤一:检查文件关联设置 首先,我们需要检查文件关联设置,确保图标文件的默认关联没有被更改为.lnk文件。按照以下步骤进行操作: 右键单击桌面上的任意图标,选择“属性”。 在弹出的属性窗口中,点击“更改图标”按钮。 在“更改图标”窗口中,检查默认的图标文件关联。如果关联被更改为.lnk文件,请…

    other 2023年8月5日
    00
  • 大势至局域网接入认证软件、禁止电脑接入局域网软件V9.0正式发布

    大势至局域网接入认证软件攻略 背景介绍 大势至局域网接入认证软件是一款用于控制用户接入局域网的安全软件。使用该软件可以限制外部电脑接入局域网,增加局域网安全性。该软件V9.0版本正式发布,下面是该软件的详细攻略。 前置要求 在使用大势至局域网接入认证软件前,需要确保以下条件: 确保已经安装了Windows操作系统 确保网络连通并拥有管理员权限 确保计算机已经…

    other 2023年6月25日
    00
  • 浅谈Java内存区域划分和内存分配策略

    浅谈Java内存区域划分和内存分配策略 Java内存区域划分和内存分配策略是Java虚拟机(JVM)管理内存的重要组成部分。了解这些概念对于理解Java程序的内存使用和性能优化至关重要。 Java内存区域划分 Java虚拟机将内存划分为以下几个区域: 程序计数器(Program Counter Register):程序计数器是一块较小的内存区域,它保存着当前…

    other 2023年8月2日
    00
  • Android自定义弹框样式

    当我们在开发 Android 应用时,可能会遇到需要自定义弹框样式的需求。下面我将分享一下 Android 自定义弹框样式的完整攻略。 步骤一:创建自定义弹框布局文件 我们首先需要创建自定义弹框的布局文件。在该布局文件中,我们可以使用任何可用的布局组件,例如 LinearLayout、RelativeLayout、TextView、ImageView、Edi…

    other 2023年6月25日
    00
  • 详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能

    详解Android使用CoordinatorLayout+AppBarLayout实现拉伸顶部图片功能攻略 在Android开发中,使用CoordinatorLayout和AppBarLayout可以实现拉伸顶部图片的功能。下面将详细介绍如何使用这两个组件来实现该功能,并提供两个示例说明。 步骤一:添加依赖 首先,在项目的build.gradle文件中添加以…

    other 2023年9月5日
    00
  • 详解iOS自定义UITabBar与布局

    详解iOS自定义UITabBar与布局 简介 UITabBarController 是 iOS 开发中常用的视图控制器之一,它的作用是实现应用程序的 Tab 切换,便于用户进行主要功能模块的选择。然而,UITabBarController 的默认布局可能不符合我们的设计需求,这时我们可以使用自定义 UITabBar 来达到定制化效果。 本文将详细阐述 iOS…

    other 2023年6月25日
    00
合作推广
合作推广
分享本页
返回顶部