刷穿剑指offer-Day13-链表III 反转链表综合进阶!

昨日回顾

昨天,我们针对链表中环与交点的题目,进行了总结。其中主要使用到的解题方法,一个是快慢指针,另外一个就是画图画图画图(重要的事情说三遍)。针对链表题,前期最重要的就是通过画图帮助理解。

今天,我们来学习链表的另外一种题型: 反转链表专题

反转链表

链表不同于数组,可以通过获取数组的长度然后递减完成逆序。

算法题目中多数的链表都是单向的,我们想获取到链表的最后一个节点就必须要挨个的遍历链表,从而得到链表尾节点。
所以链表逆序(反转)的题目就出现的理所当然了。

让我们先上一道反转链表的开胃菜,用来熟悉链表的基本操作吧。

剑指offerII024.反转链表

https://leetcode-cn.com/problems/UHnkqh/solution/shua-chuan-jian-zhi-offer-day12-lian-bia-190d/

难度:简单

题目:

给定单链表的头节点 head ,请反转链表,并返回反转后的链表的头节点。

提示:

  • 链表中节点的数目范围是 [0, 5000]
  • -5000 <= Node.val <= 5000

示例:

分析

链表不同于数组,可以通过获取数组的长度然后递减完成逆序。
日常的算法题目中链表多是单向的,我们想获取到最后一个节点就必须要挨个的遍历直到获取到链表末尾。
所以,链表逆序(反转)的题目就出现的理所当然了。
这道题是一个简单的链表逆序,主要就是考察链表的截断与重定向问题。
具体来说就是创建一个空节点,然后从链表头逐个反转。
千言万语不及画几张图,我们循环2-3的操作,即可完成链表反转...



解题:

Python:

    def reverseList(self, head):
        pre, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre, cur = cur, tmp
        return pre

Java:

class Solution {
    public ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null){
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }
}

有了这道基础的反转链表题目打底,接下来的进阶题目就有一战之力了。

相信按顺序刷力扣的朋友,都有做过第二题,两数相加。那么今天这道题是两数相加的进阶版,一起来看下吧。

剑指offerII025.链表中的两数相加

https://leetcode-cn.com/problems/lMSNwu/solution/shua-chuan-jian-zhi-offer-day13-lian-bia-cl27/

难度:中等

题目:

给定两个 非空链表 l1和 l2 来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

可以假设除了数字 0 之外,这两个数字都不会以零开头。

提示:

  • 链表的长度范围为 [1, 100]
  • 0 <= node.val <= 9
  • 输入数据保证链表代表的数字无前导 0

示例:

示例1:
输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]


示例2:
输入:l1 = [2,4,3], l2 = [5,6,4]
输出:[8,0,7]


示例3:
输入:l1 = [0], l2 = [0]
输出:[0]

分析

这道题目是力扣的第二题两数相加的进阶版本。

第二题是整数从低位向高位保存求加和, 但是这道题却是整数从高位到低位求加和的操作。

由于是单向链表,当低位存在进位时,我们没办法返回到之前的节点进行进位操作。

所以这道题,我们需要先反转链表后,在进行加法操作,最后在将加和的结果反转后输出。

由于上一道题目:

我们已经写好了反转链表的方法,所以在这里就可以直接复用了!

具体解法如下:

解题:

Python:

class Solution:
    def reverseList(self, head):
        pre, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre, cur = cur, tmp
        return pre

    def addTwoNumbers(self, l1, l2):
        rev_l1 = self.reverseList(l1)
        rev_l2 = self.reverseList(l2)
        count = 0
        ret = ListNode()
        tmp = ret
        while rev_l1 or rev_l2 or count:
            num = 0
            if rev_l1:
                num += rev_l1.val
                rev_l1 = rev_l1.next
            if rev_l2:
                num += rev_l2.val
                rev_l2 = rev_l2.next
            count, num = divmod(num + count, 10)
            tmp.next = ListNode(num)
            tmp = tmp.next
        return self.reverseList(ret.next)

Java:

class Solution {
    private ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }

    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode rev_l1 = this.reverseList(l1);
        ListNode rev_l2 = this.reverseList(l2);
        int count = 0;
        ListNode ret = new ListNode(0);
        ListNode cur = ret;
        while (rev_l1 != null || rev_l2 != null || count != 0) {
            int num = 0;
            if (rev_l1 != null) {
                num += rev_l1.val;
                rev_l1 = rev_l1.next;
            }
            if (rev_l2 != null) {
                num += rev_l2.val;
                rev_l2 = rev_l2.next;
            }
            num += count;
            count = num >= 10 ? 1 : 0;
            cur.next = new ListNode(num - count * 10);
            cur = cur.next;
        }
        return this.reverseList(ret.next);
    }
}

刚才两道题,我们都是全量反转链表的,下来这道题目,可就用到了我们之前学习到的快慢指针,配合反转链表的操作,快来看看吧。

剑指OfferII026.重排链表

https://leetcode-cn.com/problems/LGjMqU/solution/shua-chuan-jian-zhi-offer-day13-lian-bia-chs7/

难度:中等

题目

给定一个单链表 L 的头节点 head ,单链表 L 表示为:
L0→ L1→ … → Ln-1→ Ln
请将其重新排列后变为:
L0→Ln→L1→Ln-1→L2→Ln-2→ …

不能只是单纯的改变节点内部的值,而是需要实际的进行节点交换。

提示:

  • 链表的长度范围为 [1, 5 * 104]
  • 1 <= node.val <= 1000

示例

示例 1:
输入: head = [1,2,3,4]
输出: [1,4,2,3]
示例 2:
输入: head = [1,2,3,4,5]
输出: [1,5,2,4,3]

分析

如果是数组来做这道题,那真的是很简单,但偏偏它是链表你说气不气。

然而,这道题还能无脑的去使用024的整体反转链表么?答案是不能,why...
因为如果我们无脑的去反转了链表那么会将链表从1->2->3->4,转化为4->3->2->1并未解决任何问题。
不知道大家在做链表题时,是否有和我一样的感觉: 这解法就摆在眼前,一看便知,但就是写不出来.

写不出来怎么办?

  1. 先考虑下咱们之前做过的链表题目有没有类似的。注意题目关键点,将链表对半分后进行了首尾添加。
  2. 关于获取链表的一半,是不和之前咱们做过的快慢指针查找链表中间节点有关系?
  3. 找到中间节点后,如果我们将后半部分链表逆序,然后把前半部分的链表与后半部分断开。
  4. 这不就成了针对两个链表的合并题目了吗?
    让我们画图整理下思路:


最终代码如下:

解题

Python:

class Solution:
    def reverseList(self, head):
        pre, cur = None, head
        while cur:
            tmp = cur.next
            cur.next = pre
            pre, cur = cur, tmp
        return pre

    def reorderList(self, head: ListNode) -> None:
        pre = ListNode()
        pre.next = head
        slow = fast = pre
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        half = slow.next
        slow.next = None
        rev_half = self.reverseList(half)
        cur = pre.next
        while slow and rev_half:
            tmp = cur.next
            cur.next = rev_half
            cur = cur.next
            rev_half = rev_half.next
            cur.next = tmp
            cur = cur.next

Java:

class Solution {
    private ListNode reverseList(ListNode head) {
        ListNode pre = null;
        ListNode cur = head;
        while (cur != null) {
            ListNode tmp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = tmp;
        }
        return pre;
    }

    public void reorderList(ListNode head) {
        ListNode pre = new ListNode();
        ListNode slow = pre;
        ListNode fast = pre;
        pre.next = head;
        while (fast != null && fast.next != null) {
            slow = slow.next;
            fast = fast.next.next;
        }
        ListNode half = slow.next;
        slow.next = null;
        ListNode rev_half = this.reverseList(half);
        ListNode cur = pre.next;
        while (rev_half != null) {
            ListNode tmp = cur.next;
            cur.next = rev_half;
            cur = cur.next;
            rev_half = rev_half.next;
            cur.next = tmp;
            cur = cur.next;
        }
    }
}

好了,今天的链表题目整理就到这儿了。链表的题目千万不能偷懒,多在草稿纸上画画,题目就迎刃而解了,千万别偷懒啊!


加油干饭人....

欢迎关注我的公众号: 清风Python,带你每日学习Python算法刷题的同时,了解更多python小知识。

我的个人博客:https://qingfengpython.cn

力扣解题合集:https://github.com/BreezePython/AlgorithmMarkdown

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 222,252评论 6 516
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,886评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,814评论 0 361
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,869评论 1 299
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,888评论 6 398
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,475评论 1 312
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,010评论 3 422
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,924评论 0 277
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,469评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,552评论 3 342
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,680评论 1 353
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,362评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,037评论 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,519评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,621评论 1 274
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 49,099评论 3 378
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,691评论 2 361

推荐阅读更多精彩内容