链表

作者: 淡淡的橙子 | 来源:发表于2021-01-04 23:08 被阅读0次

    链表是一类大的算法题。

    一般分为一下几部分:

    • 链表反转

    • 链表合并

    我们分别进行下讨论。

    1. 链表反转
    比较典型的例子:

    链表反转I

    链表反转II

    
    Reverse a linked list from position m to n. Do it in one-pass.
    
    Input:1->2->3->4->5->NULL,m= 2,n= 4
    
    Output:1->4->3->2->5->NULL
    
    

    这个问题的写法很多,但是一个比较简介的写法是如下:

    
        public ListNode reverseBetween(ListNode head, int m, int n) {
            ListNode dummy = new ListNode();
            dummy.next = head;
            ListNode pre = dummy;
            for (int i = 0; i < m - 1; i++) {
                pre = pre.next;
            }
            ListNode start = pre.next;
            for (int i = 0; i < n - m; i++) { 
                ListNode curr = start.next;
                start.next = curr.next;
                curr.next = pre.next;
                pre.next = curr;
            }
            return dummy.next;
            
        }
    

    画一个图,就能够比较清楚的理解这个解法的思路。


    链表倒序.jpg

    也就是,pre.next代表的是倒叙开始的头,而start.next代表的是最终正序的尾。

    链表重排

    Given a singly linked list L: L0→L1→…→Ln-1→Ln,
    reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→…
    
    You may not modify the values in the list's nodes, only nodes itself may be changed.
    
    Example 1:
    Given 1->2->3->4, reorder it to 1->4->2->3.
    
    Example 2:
    Given 1->2->3->4->5, reorder it to 1->5->2->4->3.
    

    这道题最直观的思路是空间换时间,空间复杂度为O(n)。但是一个比较巧妙的算法可以不进行额外的空间消耗,空间复杂度为O(1),时时间复杂度为O(n)。
    三步解决.
    思路如下:
    第一步:找到链表的中点Lmid。

    step1.jpg
    第二步:反转中点后的链表。
    step2.jpg
    第三步:L0, L5(Lmid.next)开始进行穿插。得到最终的结果。
    代码如下:
        public void reorderList(ListNode head) {
            if (head == null) {
                return;
            }
            // 1. find Lmid
            ListNode slow = head;
            ListNode fast = head;
            while (fast.next != null && fast.next.next != null) {
                slow = slow.next;
                fast = fast.next.next;
            }
            ListNode mid = slow;
    
            // 2. reverse node after mid
            ListNode pre = mid;
            ListNode start = slow.next;
            while (start != null && start.next != null) {
                ListNode curr = start.next;
                start.next = curr.next;
                curr.next = pre.next;
                pre.next =curr;
            }
    
            // 3. merge
            ListNode p1 = head;
            ListNode p2 = pre.next;
            while (p1 != pre) {
                pre.next = p2.next;
                p2.next = p1.next;
                p1.next = p2;
                p1 = p2.next;
                p2 = pre.next;
            }
        }
    

    k翻转
    k翻转可以用递归,或者不断的使用链表翻转II的逻辑。
    我们以复用链表II的逻辑来看,实际就是k个一组进行翻转,然后移动pre和start的值即可。

    
        public ListNode reverseKGroup(ListNode head, int k) {
            int len = 0;
            ListNode curr = head;
            while(curr != null) {
                curr = curr.next;
                len++;
            }
            ListNode dummy = new ListNode();
            dummy.next = head;
            ListNode pre = dummy;
            ListNode start = pre.next;
            while (len >= k) {
                for (int i = 0; i < k - 1; i++) {
                    curr = start.next;
                    start.next = curr.next;
                    curr.next = pre.next;
                    pre.next = curr;
                }
                len -= k;
                pre = start;
                start = start.next;
            }
            return dummy.next;
        }
    

    合并K排序
    这个的一个比较简单的做法就是采用优先级队列来进行。

    public class Solution {
        public ListNode mergeKLists(List<ListNode> lists) {
            if (lists==null||lists.size()==0) return null;
            
            PriorityQueue<ListNode> queue= new PriorityQueue<ListNode>(lists.size(),new Comparator<ListNode>(){
                @Override
                public int compare(ListNode o1,ListNode o2){
                    if (o1.val<o2.val)
                        return -1;
                    else if (o1.val==o2.val)
                        return 0;
                    else 
                        return 1;
                }
            });
            
            ListNode dummy = new ListNode(0);
            ListNode tail=dummy;
            
            for (ListNode node:lists)
                if (node!=null)
                    queue.add(node);
                
            while (!queue.isEmpty()){
                tail.next=queue.poll();
                tail=tail.next;
                
                if (tail.next!=null)
                    queue.add(tail.next);
            }
            return dummy.next;
        }
    }
    

    相关文章

      网友评论

          本文标题:链表

          本文链接:https://www.haomeiwen.com/subject/mzvboktx.html