算法:反转单链表

本贴最后更新于 1263 天前,其中的信息可能已经事过景迁

对 leetCode 一个算法的分析学习,支持对单链表内指定区间的反转实现。
206. 反转链表
92. 反转链表 II

import java.util.ArrayList; import java.util.IdentityHashMap; import java.util.List; /** * 对leetCode一个算法的分析学习 * 题目:单链表的反转 * * @author hudk * @date 2020/5/27 20:20 */ public class Solution { /** * 单链表结点 */ public static class ListNode { int val; public ListNode next; public ListNode(int x) { val = x; } @Override public String toString() { return String.valueOf(val); } } /** * leetCode 题目:反转单链表1 * * 示例: * 输入: 1->2->3->4->5->NULL * 输出: 5->4->3->2->1->NULL * 进阶: * 你可以迭代或递归地反转链表。你能否用两种方法解决这道题? * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/reverse-linked-list * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 * @param head * @return */ /** * 方法一 * 这个方法是本人解答方案,相对使用了比较多的空间 * 空间复杂度:O(n) * 时间复杂度:O(n) * * @param head * @return */ public static ListNode myReverseList(ListNode head) { //当链表长度为零时,直接返回null if (head == null) { return null; } //引用指向头结点 ListNode h = head; //遍历整个链表,统计链表长度 i int i = 1; while (h.next != null) { i++; h = h.next; } //创建一个和链表长度一样的数组,并将链表的元素按照原顺序逐个放入数组中 ListNode[] ln = new ListNode[i]; for (int j = 0; j < i; j++) { ln[j] = head; head = head.next; } //再从数组的尾部开始遍历,逐个该表链表元素的next指针指向前一个元素。 for (int x = i - 1; x > 0; x--) { ln[x].next = ln[x - 1]; } //将原来的头结点(现在转置后的尾结点next引用置空) ln[0].next = null; //返回转置后新的头结点 return ln[i - 1]; } /** * 方法二 * 这个方法是leetCode上的算法大神解答的方案 * 利用递归的巧妙与优雅实现 * * 作者:labuladong * 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/bu-bu-chai-jie-ru-he-di-gui-di-fan-zhuan-lian-biao/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * @param head * @return */ public static ListNode revers(ListNode head) { if (head.next == null) { return head; } ListNode last = revers(head.next); head.next.next = head; head.next = null; return last; } /** * 方法三 * 这个方法是官方解答的方案 * 利用了迭代的思想,同样简洁且高效 * 空间复杂度:O(1) * 时间复杂度:O(n) * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/reverse-linked-list * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 * * @param head * @return */ public static ListNode reverseList(ListNode head) { ListNode prev = null; ListNode curr = head; ListNode nextTemp = null; while (curr != null) { nextTemp = curr.next; curr.next = prev; prev = curr; curr = nextTemp; } return prev; } /** * leetCode 题目:反转单链表2 * 反转从位置 m 到 n 的链表。请使用一趟扫描完成反转。 * * 说明: * 1 ≤ m ≤ n ≤ 链表长度。 * * 示例: * 输入: 1->2->3->4->5->NULL, m = 2, n = 4 * 输出: 1->4->3->2->5->NULL * * 来源:力扣(LeetCode) * 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii * 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。 */ /** * 方法一 begin******************************************************************* * <p> * 递归实现单链表的指定区间反转 * 这个算法的实现,淋漓尽致的体现了递归的优雅与简洁。 * 适用于链表长度比较短的场景,或对性能要求不高的场景 * <p> * 作者:labuladong * 链接:https://leetcode-cn.com/problems/reverse-linked-list-ii/solution/bu-bu-chai-jie-ru-he-di-gui-di-fan-zhuan-lian-biao/ * 来源:力扣(LeetCode) * 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 * * @param head * @param m * @param n * @return */ public static ListNode reverseBetween(ListNode head, int m, int n) { if(head == null){ return null; } // base case if (m == 1) { //单链表的前n个结点反转 return reverseN(head, n); } // 前进到反转的起点触发 base case head.next = reverseBetween(head.next, m - 1, n - 1); return head; } /** * 递归实现单链表的前n个结点反转 */ static ListNode successor = null; // 后驱节点 // 反转以 head 为起点的 n 个节点,返回新的头结点 public static ListNode reverseN(ListNode head, int n) { if(head == null){ return null; } if (n == 1) { // 记录第 n + 1 个节点 successor = head.next; return head; } // 以 head.next 为起点,需要反转前 n - 1 个节点 ListNode last = reverseN(head.next, n - 1); head.next.next = head; // 让反转之后的 head 节点和后面的节点连起来 head.next = successor; return last; } /**方法一end*******************************************************************/ /** * 方法二 * 这是本人的解答方案,使用了迭代的思路,并将各种情况逐一考虑,分别处理。 * 代码量比较多,但自我感觉逻辑看起来更加清晰一些。 * * @param head 链表头结点 * @param m 翻转区间开始位置 * @param n 翻转区间结束位置 * @return */ public static ListNode myReverseBetween(ListNode head, int m, int n) { if(m <= 0){ m = 1; } int size = size(head); if(n > size){ n = size; } //如果传入为空,直接返回空 if (head == null) { return null; } //如果m = n,说明转置后等于没转置,所以不做处理直接返回原链表 if (m == n) { return head; } //1、当m等于1时,倒序之后,第一个结点一定会和第n+1个结点相连 //2、并且第n个结点,会成为新链表的头结点 if (m == 1) { ListNode perv = null; ListNode crr = head; ListNode nodeOne = null; int i = 1; while (crr != null) { ListNode next = crr.next; if (i == 1) { //暂时记住第一个结点,后面它将会与第n+1个结点相连 nodeOne = crr; nodeOne.next = null; //为迭代做准备,从第2个结点开始迭代地做“翻转”动作,故将第1个结点当做下次循环时的“前置结点” perv = crr; } //从第二个结点开始,一直到第n个结点,逐一"翻转"他们的next if (i > m && i < n) { crr.next = perv; perv = crr; } //第n个结点 if (i == n) { //第一个结点的的next引用指向了第n+1个结点 nodeOne.next = crr.next; //翻转第n个结点的next crr.next = perv; //第n个结点,会成为新链表的头结点 head = crr; //由于后面得结点不需要做处理了,故跳出循环即可 break; } //迭代 crr = next; i++; } } //1、如果m>1,第m-1个结点会与第n个结点相连,第m个结点会与第n+1个结点相连 //2、然后,第m+1个到第n个结点的next依次“翻转” //3、头结点不变 if (m > 1) { ListNode perv = null; ListNode crr = head; ListNode nodeMp = null;//第m个结点的前一个结点 ListNode nodeM = null;//第m个结点 int i = 1; while (crr != null) { ListNode next = crr.next; if (i == m - 1) { //暂时记住第m-1个结点,后面它将会与第n个结点相连 nodeMp = crr; nodeMp.next = null; } if (i == m) { //暂时记住第m个结点,后面它将会与第n+1个结点相连 nodeM = crr; nodeM.next = null; //为迭代做准备,从m+1个结点开始迭代地做“翻转”动作,故将第m个结点当做下次循环时的“前置结点” perv = crr; } //第m+1个到第n个结点的next依次“翻转” if (i > m && i < n) { crr.next = perv; perv = crr; } if (i == n) { //第m个结点的next引用指向了第n+1个结点 nodeM.next = crr.next; //翻转第n个结点的next crr.next = perv; //第m-1个结点的next引用指向了第n个结点 nodeMp.next = crr; //由于后面得结点不需要做处理了,故跳出循环即可 break; } //迭代 crr = next; i++; } } return head; } /**方法二end*******************************************************************/ /** * 测试用例 * @param args */ public static void main(String[] args) { //生成一个长度为10的单链表 ListNode head = createRandomSingleLinkList(10); //打印初始链表 printLinkList(head); //反转测试 ListNode head1 = myReverseList(head); printLinkList(head1); //迭代方式反转测试 ListNode head2 = reverseList(head1); printLinkList(head2); //递归方式反转测试 ListNode head3 = revers(head2); printLinkList(head3); //迭代方式反转指定区间测试 ListNode head4 = myReverseBetween(head3,2,8); printLinkList(head4); //递归方式反转指定区间测试 ListNode head5 = reverseBetween(head4,4,5); printLinkList(head5); } /** * 生成一个指定长度的链表 * @param size * @return */ public static ListNode createRandomSingleLinkList(int size){ if(size == 0){ return null; } ListNode head = new ListNode(1); ListNode crr= head; for(int i=1; i<size; i++){ ListNode node = new ListNode(i+1); crr.next = node; crr = node; } return head; } /** * 生成 0 - 100 范围内的随机正式 * @return */ public static int randomInt(){ return (int)Math.floor(Math.random()*100); } /** * 打印链表 * @param head */ public static void printLinkList(ListNode head){ List<ListNode> nodes = new ArrayList<>(); if(head == null){ System.out.println(nodes); return; } nodes.add(head); while (head.next != null){ nodes.add(head.next); head = head.next; } System.out.println(nodes); } /** * 计算单链表长度 * @param head * @return */ public static int size(ListNode head){ if(head == null){ return 0; } int i = 1; while (head.next != null){ head = head.next; i++; } return i; } }
1 操作
hudk 在 2021-10-11 10:53:17 更新了该帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • Tomcat

    Tomcat 最早是由 Sun Microsystems 开发的一个 Servlet 容器,在 1999 年被捐献给 ASF(Apache Software Foundation),隶属于 Jakarta 项目,现在已经独立为一个顶级项目。Tomcat 主要实现了 JavaEE 中的 Servlet、JSP 规范,同时也提供 HTTP 服务,是市场上非常流行的 Java Web 容器。

    162 引用 • 529 回帖 • 2 关注
  • JetBrains

    JetBrains 是一家捷克的软件开发公司,该公司位于捷克的布拉格,并在俄国的圣彼得堡及美国麻州波士顿都设有办公室,该公司最为人所熟知的产品是 Java 编程语言开发撰写时所用的集成开发环境:IntelliJ IDEA

    18 引用 • 54 回帖
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    180 引用 • 821 回帖
  • Angular

    AngularAngularJS 的新版本。

    26 引用 • 66 回帖 • 543 关注
  • 一些有用的避坑指南。

    69 引用 • 93 回帖
  • PWA

    PWA(Progressive Web App)是 Google 在 2015 年提出、2016 年 6 月开始推广的项目。它结合了一系列现代 Web 技术,在网页应用中实现和原生应用相近的用户体验。

    14 引用 • 69 回帖 • 175 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖
  • Visio
    1 引用 • 2 回帖
  • 反馈

    Communication channel for makers and users.

    126 引用 • 929 回帖 • 265 关注
  • 音乐

    你听到信仰的声音了么?

    62 引用 • 512 回帖
  • JRebel

    JRebel 是一款 Java 虚拟机插件,它使得 Java 程序员能在不进行重部署的情况下,即时看到代码的改变对一个应用程序带来的影响。

    26 引用 • 78 回帖 • 675 关注
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    157 引用 • 290 回帖
  • BND

    BND(Baidu Netdisk Downloader)是一款图形界面的百度网盘不限速下载器,支持 Windows、Linux 和 Mac,详细介绍请看这里

    107 引用 • 1281 回帖 • 29 关注
  • Scala

    Scala 是一门多范式的编程语言,集成面向对象编程和函数式编程的各种特性。

    13 引用 • 11 回帖 • 156 关注
  • PHP

    PHP(Hypertext Preprocessor)是一种开源脚本语言。语法吸收了 C 语言、 Java 和 Perl 的特点,主要适用于 Web 开发领域,据说是世界上最好的编程语言。

    179 引用 • 408 回帖 • 483 关注
  • RYMCU

    RYMCU 致力于打造一个即严谨又活泼、专业又不失有趣,为数百万人服务的开源嵌入式知识学习交流平台。

    4 引用 • 6 回帖 • 53 关注
  • App

    App(应用程序,Application 的缩写)一般指手机软件。

    91 引用 • 384 回帖
  • Outlook
    1 引用 • 5 回帖
  • NGINX

    NGINX 是一个高性能的 HTTP 和反向代理服务器,也是一个 IMAP/POP3/SMTP 代理服务器。 NGINX 是由 Igor Sysoev 为俄罗斯访问量第二的 Rambler.ru 站点开发的,第一个公开版本 0.1.0 发布于 2004 年 10 月 4 日。

    315 引用 • 547 回帖
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 544 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • TGIF

    Thank God It's Friday! 感谢老天,总算到星期五啦!

    289 引用 • 4492 回帖 • 654 关注
  • 七牛云

    七牛云是国内领先的企业级公有云服务商,致力于打造以数据为核心的场景化 PaaS 服务。围绕富媒体场景,七牛先后推出了对象存储,融合 CDN 加速,数据通用处理,内容反垃圾服务,以及直播云服务等。

    28 引用 • 226 回帖 • 137 关注
  • 大数据

    大数据(big data)是指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。

    93 引用 • 113 回帖
  • Caddy

    Caddy 是一款默认自动启用 HTTPS 的 HTTP/2 Web 服务器。

    12 引用 • 54 回帖 • 166 关注
  • uTools

    uTools 是一个极简、插件化、跨平台的现代桌面软件。通过自由选配丰富的插件,打造你得心应手的工具集合。

    7 引用 • 27 回帖
  • 机器学习

    机器学习(Machine Learning)是一门多领域交叉学科,涉及概率论、统计学、逼近论、凸分析、算法复杂度理论等多门学科。专门研究计算机怎样模拟或实现人类的学习行为,以获取新的知识或技能,重新组织已有的知识结构使之不断改善自身的性能。

    83 引用 • 37 回帖