1. 程式人生 > 其它 >演算法題解 —— 連結串列(11-14)

演算法題解 —— 連結串列(11-14)

技術標籤:leetcode 刷題筆記資料結構演算法java連結串列

內容來源於自己的刷題筆記,對一些題目進行方法總結,用 java 語言實現。

11. 將單鏈表的每 K 個節點之間逆序:

  1. 題目描述:

    給定一個單鏈表的頭節點 head,實現一個調整單鏈表的函式,使得每 K 個節點之間逆序,如果不夠 K 個節點一組,則不調整最後幾個節點。

  2. 解題思路:

    • 方法一:利用棧結構

      • 從左到右遍歷連結串列,如果棧的大小不等於 K,就將節點不斷壓入棧中
      • 當棧的大小第一次達到 K 時,說明第一次湊齊了 K 個節點進行逆序,從棧中依次彈出這些節點,並根據彈出的順序重新連線,這一組逆序後,需要記錄一下新的頭部,同時第一組的最後一個節點(原來是頭節點)應該連線下一個節點
      • 當棧的大小每次達到 K 時,說明又湊齊了一組應該逆序的節點,從棧中依次彈出這些節點,並根據彈出的順序重新連線,直到連結串列都被遍歷完
      • 最後應該返回 newHead,作為連結串列新的頭節點
    • 方法二:在原連結串列上進行調整

      用變數記錄每一組開始的第一個節點和最後一個節點,然後直接進行調整,把這一組的節點都逆序。同樣,也是要注意第一組節點的特殊處理。

  3. 程式碼實現:

    public class ReverseKNode {
    
        private class Node{
            public int value;
            public Node next;
            public
    Node(int value){ this.value = value; } } /** * 使用棧結構 * @param head * @param K * @return */ public Node reverseKNodes1(Node head,int K){ if (K < 2) return head; Stack<Node> stack = new Stack<>(); Node newHead =
    head; Node cur = head; Node pre = null; Node next = null; while (cur != null){ next = cur.next; stack.push(cur); if (stack.size() == K){ pre = resign1(stack,pre,next); newHead = newHead == head ? cur : newHead; } cur = next; } return newHead; } public Node resign1(Stack<Node> stack,Node left,Node right){ Node cur = stack.pop(); if (left != null){ left.next = cur; } Node next = null; while (!stack.isEmpty()){ next = stack.pop(); cur.next = next; cur = next; } cur.next = right; return cur; } /** * 直接在原連結串列上進行操作 * @param head * @param K * @return */ public Node reverseKNodes2(Node head,int K){ if (K < 2){ return head; } Node cur = head; Node start = null; Node pre = null; Node next = null; int count = 1; while (cur != null){ next = cur.next; if (count == K){ start = pre == null ? head : pre.next; head = pre == null ? cur : head; resign2(pre,start,cur,next); pre = start; count = 0; } count++; } return head; } public void resign2(Node left,Node start,Node end,Node right){ Node pre = start; Node cur = start.next; Node next = null; while (cur != right){ next = cur.next; cur.next = pre; pre = cur; cur = next; } if (left != null){ left.next = end; } start.next = right; } }

12. 刪除無序連結串列中值重複出現的節點:

  1. 題目描述:

    給定一個無序單鏈表的頭節點 head,刪除其中值重複出現的節點

  2. 解題思路:

    • 方法一:利用雜湊表

      • 生成一個雜湊表,因為頭節點是不需要刪除的節點,所以首先將頭節點的值放入雜湊表
      • 從頭節點的下一個節點開始往後遍歷節點,假設遍歷到 cur 節點,先檢查 cur 的值是否在雜湊表中,如果在,則說明 cur 節點的值在之前就出現過,就將 cur 節點刪除,刪除的方式就是將最近一個沒有被刪除的節點 pre 連線到 cur 的下一個節點;如果不是,就將 cur 節點放入雜湊表中
    • 方法二:類似選擇排序的過程

      定義兩個迴圈,到第一個節點,往後迴圈是否有值相同的節點,有就刪除,以此類推,直到全部刪除完畢

  3. 程式碼實現:

    public class RemoveRep {
    
        private class Node{
            public int value;
            public Node next;
            public Node(int value){
                this.value = value;
            }
        }
    
        public void removeRep1(Node head){
            if (head == null){
                return;
            }
            HashSet<Integer> set = new HashSet<>();
            Node pre = head;
            Node cur = pre.next;
            set.add(head.value);
            while (cur != null){
                if (set.contains(cur.value)){
                    pre.next = cur.next;
                }else{
                    pre = cur;
                }
                cur = cur.next;
            }
        }
    
        public void removeRep2(Node head){
            Node cur = head;
            Node pre = null;
            Node next = null;
            while (cur != null){
                pre = cur;
                next = cur.next;
                while (next != null){
                    if (cur.value == next.value){
                        pre.next = next.next;
                    }else {
                        pre = next;
                    }
                    next = next.next;
                }
                cur = cur.next;
            }
        }
    }
    

13. 在單鏈表中刪除指定值的節點:

  1. 題目描述:

    給定一個連結串列的頭節點 head 和一個整數 num,請實現函式將值為 num 的節點全部刪除

  2. 解題思路:

    • 方法一:利用棧結構

      將值不等於 num 的節點用棧收集起來,收集完成後重新連線,最後將棧底的節點作為新的頭節點返回

    • 方法二:在原連結串列中調整

      • 從連結串列頭進行遍歷,找到第一個值不等於 num 的節點,作為新的頭節點,記為 newHead
      • 繼續往後遍歷,假設當前節點的值等於 num,就刪除;不等於就更新到最近一個不等於 num 的節點
  3. 程式碼實現:

    public class RemoveValue {
    
        private class Node{
            public int value;
            public Node next;
            public Node(int value){
                this.value = value;
            }
        }
    
        public Node removeValue1(Node head,int num){
            Stack<Node> stack = new Stack<>();
            while (head != null){
                if (head.value != num){
                    stack.push(head);
                }
                head = head.next;
            }
            while (!stack.isEmpty()){
                stack.peek().next = head;
                head = stack.pop();
            }
            return head;
        }
    
        public Node removeValue2(Node head,int num){
            while (head != null){
                if (head.value != num){
                    break;
                }
                head = head.next;
            }
            Node pre = head;
            Node cur = head;
            while (cur != null){
                if (cur.value == num){
                    pre.next = cur.next;
                }else {
                    pre = cur;
                }
                cur = cur.next;
            }
            return head;
        }
    }
    

14. 將搜尋二叉樹轉換成雙向連結串列:

  1. 題目描述:

    對二叉樹的節點來說,有本身的值域,有指向左孩子節點和右孩子節點的兩個指標;對雙向連結串列的節點來說,有本身的值域,有指向上一個節點和下一個節點的指標。在結構上,兩種結構有相似性,現在有一棵搜尋二叉樹,請將其轉換成一個有序的雙向連結串列

  2. 解題思路:

    • 方法一:使用佇列和中序遍歷
      • 生成一個佇列,記為 queue,按照二叉樹中序遍歷的順序,將每個節點放入 queue 中
      • 從 queue 中彈出節點,並按照彈出的順序重新連線所有節點
    • 方法二:利用遞迴函式
      • 構建一個類,屬性為有序雙向連結串列的頭節點和尾節點
      • 實現遞迴函式 process,先把 X 為頭的搜尋二叉樹的左子樹轉換成有序雙向連結串列,並且返回左子樹有序雙向連結串列的頭和尾,然後把以 X 為頭的搜尋二叉樹的右子樹轉換為有序雙向連結串列,並且返回右子樹有序雙向連結串列的頭和尾,接著通過 X 把兩部分連線起來
  3. 程式碼實現:

    public class Convert {
    
        private class Node{
            public int value;
            public Node left;
            public Node right;
            public Node(int value){
                this.value = value;
            }
        }
    
        /**
         * 使用佇列
         * @param head
         * @return
         */
        public Node convert1(Node head){
            Queue<Node> queue = new LinkedList<>();
            inOrderToQueue(head,queue);
            if (queue.isEmpty()){
                return head;
            }
            Node pre = head;
            pre.left = null;
            Node cur = null;
            while (!queue.isEmpty()){
                cur = queue.poll();
                pre.right = cur;
                cur.left = pre;
                pre = cur;
            }
            pre.right = null;
            return head;
        }
    
        public void inOrderToQueue(Node head,Queue<Node> queue){
            if (head == null){
                return;
            }
            inOrderToQueue(head.left,queue);
            queue.offer(head);
            inOrderToQueue(head.right,queue);
        }
    
        private class RetrunType{
            public Node start;
            public Node end;
            public RetrunType(Node start,Node end){
                this.start = start;
                this.end = end;
            }
        }
    
        public Node convert2(Node head){
            if (head == null){
                return null;
            }
            return process(head).start;
        }
    
        /**
         * 遞迴函式
         * @param head
         * @return
         */
        public RetrunType process(Node head){
            if (head == null){
                return new RetrunType(null,null);
            }
            RetrunType leftList = process(head.left);
            RetrunType rightList = process(head.right);
            if (leftList.end != null){
                leftList.end.right = head;
            }
            head.left = leftList.end;
            head.right = rightList.start;
            if (rightList.start != null){
                rightList.start.left = head;
            }
            return new RetrunType(leftList.start != null ? leftList.start : head,rightList.end != null ? rightList.end : head);
        }
    }