徒手挖地球十八周目

徒手挖地球十八周目

NO.23 合并K个排序链表 困难

在这里插入图片描述

思路一:逐一两两合并NO.21合并两个有序链表中的方法进行k-1次即可。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vhcK8eqJ-1581932915292)(https://s2.ax1x.com/2020/02/17/3C5BHU.png)]

public ListNode mergeKLists(ListNode[] lists) {
    if (lists==null||lists.length==0)return null;
    if (lists.length<2)return lists[0];
    ListNode dummy=new ListNode(-1);
    dummy.next=lists[0];
    for (int i=1;i<lists.length;i++){
        ListNode head=dummy,p=dummy.next,q=lists[i];
        while (q!=null&&p!=null){
            if (q.val< p.val){
                head.next=q;
                q=q.next;
            }else {
                head.next=p;
                p=p.next;
            }
            head=head.next;
        }
        if (q!=null)head.next=q;
        if (p!=null)head.next=p;
    }
    return dummy.next;
}

时间复杂度:O(Nk) N是节点总数,k是链表数

思路二:分治法优化两两合并 每次对折合并,0号链表和length-1号链表合并保存到0、1号链表和length-2号链表合并保存到1。。。第一轮合并后,将0~k/2再次对折两两合并。。。以此类推,最后0号链表就是最终结果。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MmWiihyt-1581932915294)(https://s2.ax1x.com/2020/02/17/3C5y4J.png)]

public ListNode mergeKLists(ListNode[] lists) {
    int len = lists.length;
    if (lists==null|| len ==0)return null;
    while (len>1){
        for (int i=0;i<len/2;i++){
            //中心对称,两两合并
            lists[i]=mergeTwoList(lists[i],lists[len-1-i]);
        }
        len=(len+1)/2;
    }
    return lists[0];
}
//合并两个链表
public ListNode mergeTwoList(ListNode l1,ListNode l2){
    ListNode dummy=new ListNode(-1);
    ListNode head=dummy,p=l1,q=l2;
    while (p!=null&&q!=null){
        if (p.val<q.val){
            head.next=p;
            p=p.next;
        }else {
            head.next=q;
            q=q.next;
        }
        head=head.next;
    }
    if (q!=null)head.next=q;
    if (p!=null)head.next=p;
    return dummy.next;
}

时间复杂度:O(Nlogk) N是节点总数,每次对折合并所有节点都参与了,一共对折合并了logk次。

NO.25 K个一组翻转链表 困难

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IB21WTPf-1581932915295)(https://s2.ax1x.com/2020/02/17/3C5wuV.png)]

思路一:迭代实现徒手挖地球九周目中NO.24两两交换链表中的节点的迭代法思路一样,不过NO.24题中的k是2而已。

  1. 哑节点dummy。pre指向待翻转子链表的前驱,end指向待翻转子链表的尾节点。然后,start指向待翻转子链表的头节点,next指向待翻转子链表的后继。最后断开待翻转子链表和剩余链表,翻转第一组。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s2XdRJHq-1581932915298)(https://s2.ax1x.com/2020/02/17/3PuodI.png)]
  2. 反转完成之后,将start节点和next节点连接。移动pre指向start节点,end指向pre节点,检查end.next不为空,所以向后移动end到下一组待翻转子链表的尾节点,start指向待翻转子链表的头节点,next指向待翻转子链表的后继。翻转第二组。[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9WdIaofT-1581932915300)(https://s2.ax1x.com/2020/02/17/3PuIeA.png)]
  3. 第二组翻转完成,将start节点和next节点连接。移动pre指向start节点,end指向pre节点,检查end.next不为空,所以向后移动end,但是剩余节点不足k个。所以翻转全部,返回dummy.next。3PKv9K.png

这里还有一个问题就是如何翻转子链表reverse(head)?用上述第一组子链表为例:

curr指向当前节点,pre指向curr之前节点,next指向curr之后节点,翻转过程比较简单,直接看图。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

public ListNode reverseKGroup(ListNode head, int k) {
    if (k==1)return head;
    //初始化哑节点、pre、end
    ListNode dummy=new ListNode(-1);
    dummy.next=head;
    ListNode pre=dummy,end=dummy;
    while (end.next!=null){
        //移动end指向待翻转子链表的尾部,如果剩余节点不足k个,则翻转完成返回head
        for (int i = 0; i < k&& end!=null; i++) end=end.next;
        if (end==null)break;
        //start指向待翻转子链表头节点,next指向未翻转部分的头节点
        ListNode start=pre.next,next=end.next;
        end.next=null;
        pre.next=reverse(start);
        //连接完成翻转部分和未翻转部分
        start.next=next;
        //移动pre和end
        pre=start;
        end=pre;
    }
    return dummy.next;
}
//翻转子链表
private ListNode reverse(ListNode head) {
    ListNode pre=null,curr=head;
    while (curr!=null){
        ListNode next=curr.next;
        curr.next=pre;
        pre=curr;
        curr=next;
    }
    return pre;
}

时间复杂度:O(nk) n是节点总数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值