1. 程式人生 > >LeetCode解題報告——Convert Sorted List to Binary Search Tree & Populating Next Right Pointers in Each Node & Word Ladder

LeetCode解題報告——Convert Sorted List to Binary Search Tree & Populating Next Right Pointers in Each Node & Word Ladder

temp 解法 slow ica sce 遍歷 iter rar ini

1. Convert Sorted List to Binary Search Tree

Given a singly linked list where elements are sorted in ascending order, convert it to a height balanced BST.

For this problem, a height-balanced binary tree is defined as a binary tree in which the depth of the two subtrees of every node never differ by more than 1.

Example:

Given the sorted linked list: [-10,-3,0,5,9],

One possible answer is: [0,-3,9,-10,null,5], which represents the following height balanced BST:

      0
     /    -3   9
   /   /
 -10  5

思路:對於樹有關的問題還是首先想到用遞歸來解決,找到中間,那麽左邊是左子樹,右邊是右子樹,以此遞歸即可。這個過程難點是找到中間的個鏈表節點,以及每次遞歸時確定左右子樹的起始範圍。

public class Solution {
    
    
public TreeNode sortedListToBST(ListNode head) { if(head==null) return null; return toBST(head,null); } public TreeNode toBST(ListNode head, ListNode tail) { //每次遞歸時左右子樹的起始,也就是鏈表中要取的頭和尾 ListNode slow = head; ListNode fast = head; if(head==tail) return
null; while(fast!=tail&&fast.next!=tail) {  //這裏很有意思,fast每次往後移動二步,slow每次往後移動一步,fast到達倒數第二個節點時,slow正好走到鏈表中間部分 fast = fast.next.next; slow = slow.next; } TreeNode thead = new TreeNode(slow.val); //取當前的中間節點作為根節點 thead.left = toBST(head,slow);  //對當前根節點的左邊鏈表部分作左子樹遞歸 thead.right = toBST(slow.next,tail);  //對當前根節點的右邊鏈表部分作右子樹遞歸 return thead; } }

2. Populating Next Right Pointers in Each Node

Given a binary tree

    struct TreeLinkNode {
      TreeLinkNode *left;
      TreeLinkNode *right;
      TreeLinkNode *next;
    }

Populate each next pointer to point to its next right node. If there is no next right node, the next pointer should be set to NULL.

Initially, all next pointers are set to NULL.

Note:

  • You may only use constant extra space.
  • You may assume that it is a perfect binary tree (ie, all leaves are at the same level, and every parent has two children).

For example,
Given the following perfect binary tree,

         1
       /        2    3
     / \  /     4  5  6  7

After calling your function, the tree should look like:

         1 -> NULL
       /        2 -> 3 -> NULL
     / \  /     4->5->6->7 -> NULL

思路:本來想通過層次便利來解題,因為隔了好久沒有做算法題,突然還是有點手生。還是看了discuss一下,有一種比較簡單的解法,還是從上往下一層層的來,對於當點節點cur,如果它有左子節點,那麽按照題目的意思它必有右子節點,那麽左子節點的next指向的是父節點的右子節點,對於這個右子節點來說,如果它的父節點的next不是null的話,那麽這個右子節點的next指向的應該是它父節點的next節點的左子節點。這樣從上往下循環即可。

public class Solution {
    public void connect(TreeLinkNode root) {
        TreeLinkNode level_start=root;
        while(level_start!=null){
            TreeLinkNode cur=level_start;
            while(cur!=null){
                if(cur.left!=null) cur.left.next=cur.right;
                if(cur.right!=null && cur.next!=null) cur.right.next=cur.next.left;
                
                cur=cur.next;
            }
            level_start=level_start.left;
        }
    }
}

上面的算法只對滿二叉樹的情形下有效,那麽如果二叉樹是任意的二叉樹時又該怎麽解題呢?比如說

Given the following binary tree,

         1
       /        2    3
     / \        4   5    7

After calling your function, the tree should look like:

         1 -> NULL
       /        2 -> 3 -> NULL
     / \        4-> 5 -> 7 -> NULL

解法和上題類似,還是一層層的從左往右遍歷,對於當前層次上的節點cur,考慮其左右子節點的情況,這個過程需要一個prev來記錄上一個鏈接中的上一個節點是什麽,以及下一層的第一節點以便後續便利。

public class Solution {
    
    //based on level order traversal
    public void connect(TreeLinkNode root) {

        TreeLinkNode head = null; //head of the next level
        TreeLinkNode prev = null; //the leading node on the next level
        TreeLinkNode cur = root;  //current node of current level

        while (cur != null) {
            
            while (cur != null) { //iterate on the current level
                //left child
                if (cur.left != null) {
                    if (prev != null) {
                        prev.next = cur.left; // 如果左子節點不是空且前一個節點不是空,直接鏈接,如果前一個節點是空,由於cur是從左到右便利的,下層第一個不是空的子節點便是下層的第一個節點
                    } else {
                        head = cur.left;
                    }
                    prev = cur.left;  // 將鏈接好的節點置為prev節點
                }
                //right child
                if (cur.right != null) {
                    if (prev != null) {
                        prev.next = cur.right;
                    } else {
                        head = cur.right;
                    }
                    prev = cur.right;
                }
                //move to next node
                cur = cur.next;
            }
            
            //move to next level
            cur = head;
            head = null;
            prev = null;
        }
        
    }
}

3. Word Ladder

Given two words (beginWord and endWord), and a dictionary‘s word list, find the length of shortest transformation sequence from beginWord to endWord, such that:

  1. Only one letter can be changed at a time.
  2. Each transformed word must exist in the word list. Note that beginWord is not a transformed word.

Note:

  • Return 0 if there is no such transformation sequence.
  • All words have the same length.
  • All words contain only lowercase alphabetic characters.
  • You may assume no duplicates in the word list.
  • You may assume beginWord and endWord are non-empty and are not the same.

Example 1:

Input:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

Output: 5

Explanation: As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.

Example 2:

Input:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

Output: 0

Explanation: The endWord "cog" is not in wordList, therefore no possible transformation.

思路:可以使用BFS來解決這題,對於beginWord,和它臨接的邊是它在wordList中所能transform到的單詞,這是第一層,那麽第二層就是第一層所能transform到的所有單詞,所以是個典型的BFS問題。試了下一般的BFS,如果從開始單詞一層層的往外找,結果會超時,所以采取兩端同時BFS,即從beginWord和endWord兩端開始BFS。

public class Solution {

    public int ladderLength(String beginWord, String endWord, Set<String> wordList) {
        if(!wordList.contains(endWord)) return 0;
        Set<String> beginSet = new HashSet<String>(), endSet = new HashSet<String>();

        int len = 1;
        HashSet<String> visited = new HashSet<String>();

        beginSet.add(beginWord);
        endSet.add(endWord);
    //    如果從beginWord到endWord的BFS或者從endWord到beginWord的BFS過程中有哪一層是空的話,則表明beginWord到endWord走不通
        while (!beginSet.isEmpty() && !endSet.isEmpty()) {
            if (beginSet.size() > endSet.size()) {    // BFS從beginWord到endWord,交換BFS方向是為了減少計算次數
                Set<String> set = beginSet;
                beginSet = endSet;
                endSet = set;    // 這裏交換beginSet和endSet來實現BFS方向的改變
            }

            Set<String> temp = new HashSet<String>();
            for (String word : beginSet) {
                char[] chs = word.toCharArray();

                for (int i = 0; i < chs.length; i++) {
                    for (char c = ‘a‘; c <= ‘z‘; c++) {
                        char old = chs[i];
                        chs[i] = c;
                        String target = String.valueOf(chs);

                        if (endSet.contains(target)) {     //     兩端BFS過程中,如果相遇則直接返回BFS深度,還要加1才是題目要求的
                            return len + 1;
                        }

                        if (!visited.contains(target) && wordList.contains(target)) {  
                            temp.add(target);
                            visited.add(target);
                        }
                        chs[i] = old;
                    }
                }
            }

            beginSet = temp;
            len++;
        }

        return 0;
    }
}

這裏的 two-end BFS,以及BFS中改變遍歷的方向以減少計算量還是很有意思的。

LeetCode解題報告——Convert Sorted List to Binary Search Tree & Populating Next Right Pointers in Each Node & Word Ladder