zoukankan      html  css  js  c++  java
  • LeetCode第[21][23]题(Java):Merge Sorted Lists

    题目:合并两个已排序链表

    难度:Easy

    题目内容

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

    翻译

    合并两个已排序的链表,并将其作为一个新链表返回。新的链表应该通过将前两个列表的节点拼接在一起。

    Example:

    Input: 1->2->4, 1->3->4
    Output: 1->1->2->3->4->4

    我的思路:数据结构——已经指定链表,且不需要特殊操作,就用链表;

         算法——对一个链表进行遍历,如果链表2节点的值小于当前节点,就插入到它前面。

            因为是单链表,所以需要前驱指针一起移动才能进行操作,并且还需要一个头节点作为返回用。

    我的代码

     1     public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
     2         if (l1 == null || l2 == null) {
     3             return l1 == null ? l2 : l1;
     4         }
     5         
     6         ListNode head = new ListNode(0);
     7         ListNode pre = head;
     8         head.next = l1;
     9         
    10         while (l1 != null && l2 != null) {
    11             if (l2.val < l1.val) {
    12                 pre.next = l2;
    13                 l2 = l2.next;
    14                 pre.next.next = l1;
    15 
    16                 pre = pre.next; // pre归位
    17                 continue;   // 插入结束,l1不需要移动
    18             }
    19             pre = l1;
    20             l1 = l1.next;
    21         }
    22         if (l2 != null) {
    23             pre.next = l2; // l2 还有剩的话说明l1已经为null,直接接在pre后面即可
    24         }
    25         return head.next;
    26     }

    我的复杂度:  时间: O(M + N)  空间: O(1)

    编码过程出现问题

    1、在插入l2之后此时l1 是不需要移动的——>continue   出错用例:[5]、[1,2,4]

    2、插入后,continue之前,还得把pre往前移动   出错用例:[5]、[1,2,4]

    参考答案代码

     1      public ListNode mergeTwoLists(ListNode l1, ListNode l2){
     2          if(l1 == null) return l2;
     3          if(l2 == null) return l1;
     4          if(l1.val < l2.val){
     5              l1.next = mergeTwoLists(l1.next, l2);
     6              return l1;
     7          } else{
     8              l2.next = mergeTwoLists(l1, l2.next);
     9              return l2;
    10          }
    11      }

    答案复杂度:  时间:O(N+M)    空间:O(N+M)

    答案思路

    利用递归的思想,每次比较之后,将小的那个节点的后继改为下一次递归返回的节点,然后返回自己。所以最后会返回l1与l2中小的那一个节点,而它的后继是一条完整的由小到大的节点。

    比较:我的那个方法空间复杂度比较好,而且由于没有使用递归运行相对较快。而答案方法则简洁明了。



    补充

    23题:Merge k Sorted Lists



    题目:就是21题的两个链表改成了k个

    难度:Hard

    我的思路:选取节点的思路肯定还是一样,选取k个链表表头中最小的那一个作为下一个节点,但是由于是k个所以在最内层也就是lists[]某一个或某几个为null的时候,就不能像两个链表一样直接返回另外一个那么简单了,就需要把原来lists中的null都给删除,但是由于是数组,所以操作起来比较麻烦得借用list。

    这种类似于多排序数组归并,其实最佳选择是堆排序,不过我嫌麻烦就直接顺序搜索最小值了。

    我的代码

     1 class Solution {
     2     public ListNode mergeKLists(ListNode[] lists) {
     3         if (lists.length == 0) {
     4             return null;
     5         }
     6         
     7         //***   去除null节点   **//
     8         List<ListNode> l = new ArrayList<ListNode>(Arrays.asList(lists));
     9         boolean hasNull = l.remove(null);
    10         lists = l.toArray(new ListNode[l.size()]);
    11         //  end  //
    12         
    13         if (hasNull) {
    14             return mergeKLists(lists);
    15         }
    16         
    17         ListNode min = getMinNode(lists);
    18         min.next = mergeKLists(lists);
    19         
    20         return min;
    21     }
    22     
    23     public static ListNode getMinNode(ListNode[] lists) {
    24         int minIndex = 0;
    25         for (int i = 1; i < lists.length; i++) {
    26             if (lists[i].val < lists[minIndex].val) {
    27                 minIndex = i;
    28             }
    29         }
    30         
    31         ListNode minNode = lists[minIndex];
    32         lists[minIndex] = lists[minIndex].next; // min取出后,lists要更新
    33         
    34         return minNode;
    35     }
    36 }

    结果:最后一两个用例栈溢出

    我的复杂度: 时间:O (N*M)    N是lists的长度,M是lists中最长的那一个

             空间:超级大。。。(因为每一次的去除null,都会新建一个lists的对应的ArrayList,并且toArray又新建了一个对应的Array),所以栈溢出了

    优化

    那就用简单粗暴的方法去除null:

    // 替换去除null //
            for (int i = 0; i < lists.length; i++) {
                if (lists[i] == null) {
                    ListNode[] temp = new ListNode[lists.length-1];
                    for (int j = 0; j < temp.length; j++) {
                        if (j < i) {
                            temp[j] = lists[j];
                        } else {
                            temp[j] = lists[j+1];
                        }
                    }
                    hasNull = true;
                    lists = temp;
                    i--;
                }
            }
    // end//

    这样一来就只多建了一个temp的Array。

    【注意】:最后在数组删除元素之后不要忘了  i -- ,因为当前的i已经被删除了,最新的lists第i个已经是以前的第i+1个,如果继续循环那么将直接 i ++ 就会跳过之前的那个 i + 1。

    优化后结果:不溢出了。。。但是运行超时了。

    好吧看来还是得用堆排序——优先队列。

    答案代码

     1 class Solution {
     2     public ListNode mergeKLists(ListNode[] lists) {
     3         ListNode res=null;
     4 
     5         System.out.println("lists.length "+ lists.length);
     6         if(lists == null || lists.length== 0)
     7             return res;
     8       
     9         PriorityQueue pq = new PriorityQueue();
    10         for(int i=0; i<lists.length; i++){
    11             if(lists[i]!=null){
    12                 pq.offer(new PQNode(lists[i].val, 0, i));
    13                 lists[i] = lists[i].next;
    14             }
    15         }
    16         
    17         
    18         for(int i=0; !pq.isEmpty(); i++){
    19             PQNode n = (PQNode)pq.poll();
    20             int value = n.value;
    21             int index = n.index;
    22             int listNumber = n.listNumber;
    23             if(res==null){
    24                 res = new ListNode(value);
    25             }
    26             else{
    27                 ListNode temp = res;
    28                 while(temp.next!=null){
    29                     temp=temp.next;
    30                 }
    31                 temp.next = new ListNode(value);
    32             }
    33             if(lists[listNumber]!=null){
    34                 pq.offer(new PQNode(lists[listNumber].val, 0, listNumber));
    35                 lists[listNumber] = lists[listNumber].next;
    36 
    37             }
    38         }
    39         return res;
    40     }
    41 }
    42 
    43 class PQNode implements Comparable<PQNode>{
    44     int value;
    45     int index;
    46     int listNumber;
    47     
    48     public PQNode(int value, int index, int listNumber){
    49         this.value = value;
    50         this.index = index;
    51         this.listNumber = listNumber;
    52     }
    53     
    54     public int compareTo(PQNode obj){
    55         if(this.value < obj.value) return -1;
    56         if(this.value > obj.value) return 1;
    57         return 0;
    58     }
    59 }

    答案复杂度: 时间:O (N*logM + M)   空间:O(M)

    答案思路:思路没变,不过就是在取k个数组中最小的时候使用了一个优先级队列——最开始将k个链表头取出建立一个优先级队列(java.util.PriorityQueue),然后每次poll

    出队头后再放进此队头原来所在链表的链表头,当发现此表头为null的时候,则优先级队列的大小减一。直到队列为空。

  • 相关阅读:
    批量修改文件的编码格式至UTF-8
    springboot搭建
    Redit集群搭建-Sentinel模式搭建
    Java并发编程:深入剖析ThreadLocal
    Hibernate常见问题 No row with the given identifier exists问题的解决办法及解决
    vector删除元素与清除内存空洞
    BZOJ 1003 [ZJOI2006]物流运输trans SPFA+DP
    Mybatis+Oracle批处理
    【日常学习】【线性DP】codevs1044 拦截导弹题解
    hdu5353 Average
  • 原文地址:https://www.cnblogs.com/Xieyang-blog/p/8921277.html
Copyright © 2011-2022 走看看