算法:反转单链表

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

对 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 更新了该帖

相关帖子

欢迎来到这里!

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

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

推荐标签 标签

  • 服务器

    服务器,也称伺服器,是提供计算服务的设备。由于服务器需要响应服务请求,并进行处理,因此一般来说服务器应具备承担服务并且保障服务的能力。

    125 引用 • 585 回帖
  • Hexo

    Hexo 是一款快速、简洁且高效的博客框架,使用 Node.js 编写。

    22 引用 • 148 回帖 • 17 关注
  • 京东

    京东是中国最大的自营式电商企业,2015 年第一季度在中国自营式 B2C 电商市场的占有率为 56.3%。2014 年 5 月,京东在美国纳斯达克证券交易所正式挂牌上市(股票代码:JD),是中国第一个成功赴美上市的大型综合型电商平台,与腾讯、百度等中国互联网巨头共同跻身全球前十大互联网公司排行榜。

    14 引用 • 102 回帖 • 316 关注
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖
  • Pipe

    Pipe 是一款小而美的开源博客平台。Pipe 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    133 引用 • 1124 回帖 • 109 关注
  • 电影

    这是一个不能说的秘密。

    122 引用 • 608 回帖
  • wolai

    我来 wolai:不仅仅是未来的云端笔记!

    2 引用 • 14 回帖 • 6 关注
  • 国际化

    i18n(其来源是英文单词 internationalization 的首末字符 i 和 n,18 为中间的字符数)是“国际化”的简称。对程序来说,国际化是指在不修改代码的情况下,能根据不同语言及地区显示相应的界面。

    8 引用 • 26 回帖 • 4 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖
  • 黑曜石

    黑曜石是一款强大的知识库工具,支持本地 Markdown 文件编辑,支持双向链接和关系图。

    A second brain, for you, forever.

    24 引用 • 241 回帖
  • Laravel

    Laravel 是一套简洁、优雅的 PHP Web 开发框架。它采用 MVC 设计,是一款崇尚开发效率的全栈框架。

    20 引用 • 23 回帖 • 740 关注
  • NGINX

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

    315 引用 • 547 回帖 • 1 关注
  • 思源笔记

    思源笔记是一款隐私优先的个人知识管理系统,支持完全离线使用,同时也支持端到端加密同步。

    融合块、大纲和双向链接,重构你的思维。

    25523 引用 • 105573 回帖 • 1 关注
  • IPFS

    IPFS(InterPlanetary File System,星际文件系统)是永久的、去中心化保存和共享文件的方法,这是一种内容可寻址、版本化、点对点超媒体的分布式协议。请浏览 IPFS 入门笔记了解更多细节。

    21 引用 • 245 回帖 • 227 关注
  • 程序员

    程序员是从事程序开发、程序维护的专业人员。

    589 引用 • 3538 回帖
  • 持续集成

    持续集成(Continuous Integration)是一种软件开发实践,即团队开发成员经常集成他们的工作,通过每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试)来验证,从而尽早地发现集成错误。

    15 引用 • 7 回帖 • 2 关注
  • 倾城之链
    23 引用 • 66 回帖 • 167 关注
  • Q&A

    提问之前请先看《提问的智慧》,好的问题比好的答案更有价值。

    9766 引用 • 44433 回帖 • 88 关注
  • React

    React 是 Facebook 开源的一个用于构建 UI 的 JavaScript 库。

    195 引用 • 291 回帖 • 373 关注
  • VirtualBox

    VirtualBox 是一款开源虚拟机软件,最早由德国 Innotek 公司开发,由 Sun Microsystems 公司出品的软件,使用 Qt 编写,在 Sun 被 Oracle 收购后正式更名成 Oracle VM VirtualBox。

    10 引用 • 2 回帖 • 17 关注
  • 深度学习

    深度学习(Deep Learning)是机器学习的分支,是一种试图使用包含复杂结构或由多重非线性变换构成的多个处理层对数据进行高层抽象的算法。

    54 引用 • 44 回帖 • 1 关注
  • jsoup

    jsoup 是一款 Java 的 HTML 解析器,可直接解析某个 URL 地址、HTML 文本内容。它提供了一套非常省力的 API,可通过 DOM,CSS 以及类似于 jQuery 的操作方法来取出和操作数据。

    6 引用 • 1 回帖 • 487 关注
  • 百度

    百度(Nasdaq:BIDU)是全球最大的中文搜索引擎、最大的中文网站。2000 年 1 月由李彦宏创立于北京中关村,致力于向人们提供“简单,可依赖”的信息获取方式。“百度”二字源于中国宋朝词人辛弃疾的《青玉案·元夕》词句“众里寻他千百度”,象征着百度对中文信息检索技术的执著追求。

    63 引用 • 785 回帖 • 91 关注
  • MongoDB

    MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是一个基于分布式文件存储的数据库,由 C++ 语言编写。旨在为应用提供可扩展的高性能数据存储解决方案。MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。

    91 引用 • 59 回帖 • 2 关注
  • 叶归
    8 引用 • 38 回帖 • 18 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 636 关注
  • Firefox

    Mozilla Firefox 中文俗称“火狐”(正式缩写为 Fx 或 fx,非正式缩写为 FF),是一个开源的网页浏览器,使用 Gecko 排版引擎,支持多种操作系统,如 Windows、OSX 及 Linux 等。

    7 引用 • 30 回帖 • 386 关注