算法系列--链表刷题(二)(下)

简介: 算法系列--链表刷题(二)(下)

算法系列--链表刷题(二)(上)

https://developer.aliyun.com/article/1480808?spm=a2c6h.13148508.setting.14.5f4e4f0e08yH7p

4.合并 K 个升序链表(hard)

链接:

https://leetcode.cn/problems/merge-k-sorted-lists/description/

分析:

思路一:利用优先级队列

其实本题和合并两个有序链表很相似,可以看做是上一题的plus版本

虽然这里是合并K个有序链表,但是我们可以借鉴合并两个有序链表的思路,`创建一个傀儡节点,找到两个链表节点的最小值,依次插入到傀儡节点之后

这里的难点在于如果只有两个节点,我们可以直接比较,但是现在有K个节点,如何快速地找到K个节点的最小值呢?使用优先级队列,利用优先级队列将K个链表的头结点存入到优先级队列之中,由于默认是小根堆,所以堆顶元素就是K个链表头结点的最大值,将其插入到傀儡节点之后,更新傀儡节点,然后插入堆顶节点的下一个节点,接着判断最小值,重复上述过程

手写:

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        PriorityQueue<ListNode> heap = new PriorityQueue<>((o1,o2) ->o1.val - o2.val);
        ListNode ret = new ListNode(0);
        ListNode phead = ret;
        for(ListNode head : lists)// 将链表的头结点存入堆中
            if(head != null)
                heap.offer(head);
        while(!heap.isEmpty()) {
            ListNode tmp = heap.poll();
            phead.next = tmp;
            phead = tmp;
            if(tmp.next != null) heap.offer(tmp.next);// 注意下一个节点可能为空
        }
        return ret.next;
    }
}

思路二:利用归并的思想

其实这道题非常符合分治归并的思想,题目相当于给了我们一个比较特殊的数组(数组的元素是链表),实际上最重要完成的工作就是对这K个元素进行从小到大的排序,既然是排序我们就可以使用归并的思想,为什么想到归并呢?这是经过分析得到的,实际上我们是对一个一个的链表进行合并+排序操作的,这一步其实就是归并中分解到最小单元,开始回并的过程啊!所以可以使用归并的思想解决

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if(lists == null || lists.length == 0) return null;
        // 采用归并的思想解决
        return merge(lists,0,lists.length-1);
    }
    public ListNode merge(ListNode[] lists,int left,int right) {
        // 递归出口
        if(left >= right) return lists[left];
        int mid = (left + right) /2;
        ListNode l1 = merge(lists,left,mid);
        ListNode l2 = merge(lists,mid + 1,right);
        return mergeTwoLists(l1,l2);
    }
    // 合并两个有序链表
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        // 递归
        if(list1 == null) return list2;
        if(list2 == null) return list1;
        if(list1.val < list2.val) {
            list1.next = mergeTwoLists(list1.next,list2);
            return list1;
        }else {
            list2.next = mergeTwoLists(list2.next,list1);
            return list2;
        }
    }
}

5.K个⼀组翻转链表

链接:

https://leetcode.cn/problems/reverse-nodes-in-k-group/description/

分析:

本题采用模拟的思想,具体的模拟策略如下:

  1. 求出要反转多少个长度为K的链表–n
  2. 翻转n次即可

代码:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        // 求需要翻转的组数n
        int cnt = 0;
        ListNode tmp = head;
        while(tmp != null) {
            cnt++;
            tmp = tmp.next;
        }
        int n = cnt / k;
        // 开始进行翻转
        ListNode ret = new ListNode(0);
        ListNode phead = ret;
        ListNode cur = head;
        for(int i = 0; i < n; i++) {
            ListNode prev = cur;// 保存当前翻转链表的头结点
            for(int j = 0; j < k; j++) {
                ListNode curnext = cur.next;
                cur.next = phead.next;
                phead.next = cur;
                cur = curnext;
            }
            phead = prev;// 每翻转完一组就更新phead
        }
        phead.next = cur;
        return ret.next;
    }
}


目录
相关文章
|
1月前
|
程序员
【刷题记录】移除链表元素
【刷题记录】移除链表元素
|
1月前
【刷题记录】链表的回文结构
【刷题记录】链表的回文结构
|
1月前
|
算法
【算法】合并两个有序链表(easy)——递归算法
【算法】合并两个有序链表(easy)——递归算法
【算法】合并两个有序链表(easy)——递归算法
|
1月前
|
存储 算法
【初阶数据结构篇】顺序表和链表算法题
此题可以先找到中间节点,然后把后半部分逆置,最近前后两部分一一比对,如果节点的值全部相同,则即为回文。
|
1月前
|
算法
【数据结构与算法】共享双向链表
【数据结构与算法】共享双向链表
11 0
|
1月前
|
算法
【数据结构与算法】双向链表
【数据结构与算法】双向链表
10 0
|
1月前
|
算法
【数据结构与算法】循环链表
【数据结构与算法】循环链表
12 0
|
1月前
|
存储 算法
【数据结构与算法】链表
【数据结构与算法】链表
16 0
|
1月前
|
机器学习/深度学习
【刷题记录】相交链表
【刷题记录】相交链表
|
1月前
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)
【刷题记录】最大公因数,最小公倍数(辗转相除法、欧几里得算法)