标签: 链表

LeetCode刷题【114】二叉树展开为链表

给你二叉树的根结点 root ,请你将它展开为一个单链表:

  • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
  • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

 

示例 1:

输入:root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]

示例 2:

输入:root = []
输出:[]

示例 3:

输入:root = [0]
输出:[0]

 

提示:

  • 树中结点数在范围 [0, 2000]
  • -100 <= Node.val <= 100

 

进阶:你可以使用原地算法(O(1) 额外空间)展开这棵树吗?

Related Topics
  • 深度优先搜索
  • 链表
  • 二叉树

  • 👍 1219
  • 👎 0
  • 前序遍历,原地递归修改
    按照题意为前序遍历的结果,声明一个TreeNode pre记录前一个访问的节点

    这样直接进行前序遍历,把当前节点挂载到pre节点的right上,记得要清除left节点

    遍历当前节点的时候leftright节点的值记得先存下来,会在递归的时候被修改掉

    代码

    class Solution {
        /*
            1
        2       5
      3   4   n   6
    
            1
          n   2
            n   3
              n   4
                n   5
                  n   6
    
         */
        TreeNode pre;
        public void flatten(TreeNode root) {
            dfs(root);
        }
    
    
        public void dfs(TreeNode node){
            if (null == node){
                return;
            }
            if (pre!=null){
                pre.right = node;
            }
            pre = node;
            TreeNode left = node.left;
            TreeNode right = node.right;
            node.left = null;
            dfs(left);
            dfs(right);
        }
    }

    LeetCode刷题【19】删除链表的倒数第 N 个结点

    给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。

     

    示例 1:

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

    示例 2:

    输入:head = [1], n = 1
    输出:[]
    

    示例 3:

    输入:head = [1,2], n = 1
    输出:[1]
    

     

    提示:

    • 链表中结点的数目为 sz
    • 1 <= sz <= 30
    • 0 <= Node.val <= 100
    • 1 <= n <= sz

     

    进阶:你能尝试使用一趟扫描实现吗?

    Related Topics
    • 链表
    • 双指针

  • 👍 2102
  • 👎 0
  • 双指针

    1. 定义俩指针,右指针先往后跑N位,之后一起往后跑,当右指针到结尾的时候左边那个指针就是要删除的节点
    2. 因为要删除的是左边这个节点,所以可以先把右指针往右再多移动一位,再和左指针一起往后跑,停下来的时候,左指针的next指向到next的next
    3. 如果第一开始先跑N位的时候,已经跑到了结尾,则说明要删除的是头结点,直接返回头结点的next
    4. 本题不支持输入的n大于链表长度的情况
    class Solution {
        public ListNode removeNthFromEnd(ListNode head, int n) {
            ListNode curN = head;
            while (--n >= 0 && curN != null){
                curN = curN.next;
            }
            if (curN==null){
                return head.next;
            }
            ListNode cur = head;
            curN = curN.next;
            while (curN != null){
                cur = cur.next;
                curN = curN.next;
            }
            cur.next = cur.next.next;
            return head;
        }
    }

    LeetCode刷题【21】合并两个有序链表

    将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 

     

    示例 1:

    输入:l1 = [1,2,4], l2 = [1,3,4]
    输出:[1,1,2,3,4,4]
    

    示例 2:

    输入:l1 = [], l2 = []
    输出:[]
    

    示例 3:

    输入:l1 = [], l2 = [0]
    输出:[0]
    

     

    提示:

    • 两个链表的节点数目范围是 [0, 50]
    • -100 <= Node.val <= 100
    • l1l2 均按 非递减顺序 排列
    Related Topics
  • 递归
  • 链表

  • 👍 2490
  • 👎 0
  • 双指针,串珠子

    剑指Offer25
    这个问题之前给人家形象的比喻讲解过。

    1. 你拿两串珠子,分别按照题意标上有序递增的数字
    2. 另外你再拿一根线,把这两串珠子合并成一串,这时候你会怎么做呢?
      当然是两个原串头上挑小的串起来呀!哪个小串哪个,另外一串没有了就整个串上就完了
    class Solution {
        public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            ListNode head = new ListNode();
            ListNode cur = head;
            while ( l1 != null || l2 != null ){
                if (l1 == null || l2 == null){
                    cur.next = l1==null?l2:l1;
                    break;
                }
                if (l1.val < l2.val){
                    cur.next = l1;
                    l1 = l1.next;
                }else{
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
            return head.next;
        }
    }
    

    LeetCode刷题【剑指 Offer 24】反转链表

    定义一个函数,输入一个链表的头节点,反转该链表并输出反转后链表的头节点。

     

    示例:

    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL

     

    限制:

    0 <= 节点个数 <= 5000

     

    注意:本题与主站 206 题相同:https://leetcode-cn.com/problems/reverse-linked-list/

    Related Topics
  • 递归
  • 链表

  • 👍 448
  • 👎 0
  • 遍历修改指针

    修改指针

    操作简单

    1. 把当前节点的next指向之前遍历的节点pre,这是核心
    2. 因为进行了上一步操作之后下一个节点就找不到了,所以需要一个变量暂存一下修改之前的next指向
    3. 同时pre指向跟随遍历窗口移动到当前节点
    4. 同时需要把当前移动到原链表的下一个节点,也就是步骤(2)中记下的那个
    5. 到结束时遍历到原链表的结尾null节点,此时pre指向为原链表的结尾非空那个节点,也就是翻转后的头结点

    代码

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

    LeetCode刷题【剑指 Offer 25】合并两个排序的链表

    输入两个递增排序的链表,合并这两个链表并使新链表中的节点仍然是递增排序的。

    示例1:

    输入:1->2->4, 1->3->4
    输出:1->1->2->3->4->4

    限制:

    0 <= 链表长度 <= 1000

    注意:本题与主站 21 题相同:https://leetcode-cn.com/problems/merge-two-sorted-lists/

    Related Topics
  • 递归
  • 链表

  • 👍 254
  • 👎 0
  • 双指针合并,不如找两串珠子自己比划比划

    这个问题之前给人家形象的比喻讲解过。

    1. 你拿两串珠子,分别按照题意标上有序递增的数字
    2. 另外你再拿一根线,把这两串珠子合并成一串,这时候你会怎么做呢?
    3. 当然是两个原串头上挑小的串起来呀!哪个小串哪个,另外一串没有了就整个串上就完了

    代码

    class Solution {
        public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
            ListNode head = new ListNode();
            ListNode cur = head;
            while ( l1 != null || l2 != null ){
                if (l1 == null || l2 == null){
                    cur.next = l1==null?l2:l1;
                    break;
                }
                if (l1.val < l2.val){
                    cur.next = l1;
                    l1 = l1.next;
                }else{
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
            return head.next;
        }
    }

    如果本题能够很好理解了不妨再去试试23. 合并K个升序链表
    题解JAVA 分治归并 其实挺简单的

    LeetCode刷题【23】合并K个升序链表

    给你一个链表数组,每个链表都已经按升序排列。

    请你将所有链表合并到一个升序链表中,返回合并后的链表。

     

    示例 1:

    输入:lists = [[1,4,5],[1,3,4],[2,6]]
    输出:[1,1,2,3,4,4,5,6]
    解释:链表数组如下:
    [
      1->4->5,
      1->3->4,
      2->6
    ]
    将它们合并到一个有序链表中得到。
    1->1->2->3->4->4->5->6
    

    示例 2:

    输入:lists = []
    输出:[]
    

    示例 3:

    输入:lists = [[]]
    输出:[]
    

     

    提示:

    • k == lists.length
    • 0 <= k <= 10^4
    • 0 <= lists[i].length <= 500
    • -10^4 <= lists[i][j] <= 10^4
    • lists[i]升序 排列
    • lists[i].length 的总和不超过 10^4
    Related Topics
  • 链表
  • 分治
  • 堆(优先队列)
  • 归并排序

  • 👍 2025
  • 👎 0
  • JAVA 分治归并 其实挺简单的

    1. 对于K个链表,可以两两合并(有点归并排序的意思)
    2. 一次合并完了之后此时变成K/2个链表了,对剩下的链表继续两两合并
    3. 最终全都合并到了一个链表里
    4. 至于两个链表的合并过程,直接参考剑指Offer25题,比较简单算链表基本题了吧,我之前写的题解双指针合并,不如找两串珠子自己比划比划
    5. 至于如何选择两两的过程可以简单设计下
    //对应为k个链表在入参数组中的下标
    1 [0,1],[2,3],[4,5],[6,7],[8]
    2 [0,2],[4,6],[8]
    4 [0,4],[8]
    8 [0,8]
    
    - 第一次 `[0,1],[2,3],[4,5],[6,7]`互相合并,结果留在第一个链表位置, `[8]`单独拉下了没关系先留着
    - 第二次 `[0,2],[4,6]` 互相合并,结果存在0 , 4 位置,8继续留着,`[8]`没关系
    - 第三次 再次合并`[0,4]`,`[8]`继续留着
    - 最后一次合并`[0,8]`结束收工
    class Solution {
        public ListNode mergeKLists(ListNode[] lists) {
            if (lists.length == 1){
                return lists[0];
            }
            if (lists.length == 0){
                return null;
            }
            int dis = 1;
            while (dis < lists.length){
                //1 [0,1],[2,3],[4,5],[6,7],[8]
                //2 [0,2],[4,6],[8]
                //4 [0,4],[8]
                //8 [0,8]
                for (int i = 0; i + dis < lists.length; i += dis*2) {
                    //合并两个有序链表  剑指Offer25题
                    lists[i] = mergeTwoLists(lists[i],lists[i+dis]);
                    lists[i+dis] = null;
                }
                dis *=2;
            }
            return lists[0];
        }
    
        public ListNode mergeTwoLists(ListNode l1, ListNode l2){
            ListNode head = new ListNode();
            ListNode cur = head;
            while ( l1 != null || l2 != null ){
                if (l1 == null || l2 == null){
                    cur.next = l1==null?l2:l1;
                    break;
                }
                if (l1.val < l2.val){
                    cur.next = l1;
                    l1 = l1.next;
                }else{
                    cur.next = l2;
                    l2 = l2.next;
                }
                cur = cur.next;
            }
            return head.next;
        }
    }

    LeetCode刷题【剑指 Offer 18】删除链表的节点

    给定单向链表的头指针和一个要删除的节点的值,定义一个函数删除该节点。

    返回删除后的链表的头节点。

    注意:此题对比原题有改动

    示例 1:

    输入: head = [4,5,1,9], val = 5
    输出: [4,1,9]
    解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
    

    示例 2:

    输入: head = [4,5,1,9], val = 1
    输出: [4,5,9]
    解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.
    

     

    说明:

    • 题目保证链表中节点的值互不相同
    • 若使用 C 或 C++ 语言,你不需要 freedelete 被删除的节点
    Related Topics
  • 链表

  • 👍 232
  • 👎 0
  • 遍历修改引用

    基本分析

    1. 删除头结点的操作作为特殊情况处理,直接返回头结点的下一个节点
    2. 遍历链表,找到值等于val的节点,
    3. 遍历的时候还要有个变量记下前一个节点是谁,
    4. 直接把前一个节点的next指向当前值为val的节点的next节点
    5. 注意一些遍历的边界情况
      • 比如没有找到匹配的val的节点的话,最红对链表结尾的判定
      • 比如加入链表长度只有1,且val也没有匹配这个节点的值的话pre节点依旧为null
      • 该有比如,假如链表里值为val的节点不止一个的话怎么处理呢?本题好像没这个情况

    代码

    class Solution {
        public ListNode deleteNode(ListNode head, int val) {
            if (head==null){
                return head;
            }
            if (head.val == val){
                return head.next;
            }
    
            ListNode cur = head;
            ListNode pre = null;
            while (val != cur.val && cur != null){
                pre = cur;
                cur = cur.next;
            }
            if (null!=pre){
                pre.next = cur.next;
            }
            return head;
        }
    }