leetcode 两数相除、合并K个链表

1. 两数相除

  

  题目很简单(但还是错了几十遍), 思路是将除数翻倍地增大,超出被除数范围后,用被除数本应剩余的值继续重复操作。

  需要注意的点: 因为是翻倍操作,很可能会出现除数翻倍后超过int 范围,所以需要用Long 类型

         Math.abs() 函数,在使用时要 Math.abs((long) c) 因为最小值的绝对值超过了Int 范围, 所以这样使用才能保证得到准确的值

    代码:

2. 合并 K 个有序链表

  

  几种思路: 1. 将所有元素挨个添加到数组中, Arrays.sort() 排序,然后逐个添加进新链表

        Arrays.sort() 时间复杂度为 O(NlogN) 比较暴力,效率低

       2. 最小堆,保存每个链表的头,依次将最小的添加进新链表,因为堆每次操作时间复杂度为 logk (k 是链表个数,即堆的大小)

        一共 N 个节点,要操作N 次, 所以时间复杂度为 NlogK  ,效率大大提高

       3. 分治法。 因为之前做过将两个有序链表合并的题目,其时间复杂度为 O(N),(N是两个链表的总节点数)

        将链表两两合并,每次合并链表数目都会减半,每次合并都会遍历所有节点,即N次

        K减半至1 ,需要 LogK 次,所以时间复杂度同样为 O(NlogK) 

    最小堆代码:

 public ListNode mergeKLists(ListNode[] lists) {
        MinHeap pq = new MinHeap(lists.length);
        for (int i = 0; i < lists.length; i++) {
            if (lists[i] != null) {
                pq.add(lists[i]);
            }
        }
        ListNode dummyHead = new ListNode(0);
        ListNode cur = dummyHead;
        while (!pq.isEmpty()) {
            ListNode node = pq.extractMin();
            cur.next = node;
            cur = node;
            if (node.next != null) {
                pq.add(node.next);
            }
        }
        return dummyHead.next;
    }

    private class MinHeap {
        private ListNode[] data;
        private int capacity;
        private int size;

        public MinHeap(int capacity) {
            this.capacity = capacity;
            data = new ListNode[capacity];
            size = 0;
        }
        
        public boolean isEmpty() {
            return size == 0;
        }
        
        public void add(ListNode node) {
            if (size == capacity) {
                throw new IllegalArgumentException("heap is full.");
            }
            data[size] = node;
            shiftUp(size);
            size++;
        }
        
        private void swap(int i, int j) {
            ListNode temp = data[i];
            data[i] = data[j];
            data[j] = temp;
        }
        
        private void shiftUp(int k) {
            while (k > 0 && data[k].val < data[(k - 1) / 2].val) {
                int parent = (k - 1) / 2;
                swap(k, parent);
                k = parent;
            }
        }
        
        public ListNode extractMin() {
            if (size == 0) {
                throw new IllegalArgumentException("heap is empty...");
            }
            ListNode ret = data[0];
            data[0] = data[--size];
            shiftDown(0);
            return ret;
        }
        
        private void shiftDown(int k) {
            while (2 * k + 1 < size) {
                int j = 2 * k + 1;
                if (j + 1 < size && data[j + 1].val < data[j].val) {
                    j++;
                }
                if (data[k].val <= data[j].val) {
                    break;
                }
                swap(k, j);
                k = j;
            }
        }
        
    }

 代码来自  leetcode :  lmz

   分治法代码: 

public ListNode mergeKLists(ListNode[] lists) {
        if(lists==null||lists.length==0)return null;
        //ListNode head = new ListNode(1);
        int len = lists.length;
        int ind = 1;
        while (ind <len) {
            for(int i =0;i<len - ind;i+=2*ind){
                lists[i] = mergeTwoLists(lists[i],lists[i+ind]);
            }
            ind *=2;
        }
        return lists[0];
    }
     public  ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if (l1 == null && l2 == null) return null;
        if (l1 == null) return l2;
        if (l2 == null) return l1;
        ListNode head, hd = l1;
        if (l1.val > l2.val) {
            hd = l2;
            l2 = l2.next;
        } else l1 = l1.next;
        head = hd;
        while (l1 != null && l2 != null) {
            if (l1.val > l2.val) {
                head.next = l2;
                l2 = l2.next;
            } else {
                head.next = l1;
                l1 = l1.next;
            }
            head = head.next;
        }
        while (l1 != null) {
            head.next = l1;
            l1 = l1.next;
            head = head.next;
        }
        while (l2 != null) {
            head.next = l2;
            l2 = l2.next;
            head = head.next;
        }
        return hd;
    }

    

    PS: 之前用 PriorityQueue ,耗时一直是分治法的十几倍,后来才知道 PriorityQueue的复杂度比自己写的最小堆要高,

猜你喜欢

转载自www.cnblogs.com/xfdmyghdx/p/11070023.html