個人面試準備過程--leetcode樹

 由遍歷結果反求樹

分析:遞歸分治,第一層須要找到相應的遍歷結果,對數組來講,問題轉化爲找下標問題
對前序、中序遍歷結果來講
前序:[root,[左],[右]]
中序:[[左],root,[右]]
所以,中序中root的下標可求,爲inorderPos數組

對每一層來講,左子樹的長度爲leftLen = inorderPos,右子樹的長度爲rightLen = inorder.length - 1 - leftLen,
左子樹前序爲preorder[1 至 leftLen],中序爲inorder[0 至 leftLen - 1],能夠使用System.arraycopy(preorder, 1, leftPre, 0, leftLen),
System.arraycopy(inorder, 0, leftInorder, 0, leftLen);
右子樹前序爲preorder[leftLen + 1 至 preorder.length - 1],中序爲inorder[leftLen + 1 至 inorder.lenth - 1],能夠使用System.arraycopy(preorder, leftLen + 1, rightPre, 0, rightLen),System.arraycopy(inorder, leftLen + 1, rightInorder, 0, rightLen);

對中序、後序來講,
中序:[[左],root,[右]]
後序:[[左],[右],root]函數

Leetcode 105 由前序、中序構建樹

public TreeNode buildTree(int[] preorder, int[] inorder) {
    if(preorder.length == 0 || inorder.length == 0 || preorder.length != inorder.length){
        return null;
    }

    int len = preorder.length;
    TreeNode root = new TreeNode(preorder[0]);
    int inorderPos = 0;
    for(; inorderPos < inorder.length; inorderPos++){
        if(inorder[inorderPos] == root.val){
            break;
        }
    }

    int leftLen = inorderPos;
    int rightLen = len - inorderPos - 1;

    int[] leftPre = new int[leftLen];
    int[] leftInorder = new int[leftLen];

    int[] rightPre = new int[rightLen];
    int[] rightInorder = new int[rightLen];

    for(int i = 0; i < leftLen; i++){
        leftPre[i] = preorder[i + 1];
        leftInorder[i] = inorder[i];
    }

    for(int i = 0; i < rightLen; i++){
        rightPre[i] = preorder[leftLen + 1 + i];
        rightInorder[i] = inorder[leftLen + 1 + i];
    }

    TreeNode left = buildTree(leftPre, leftInorder);
    TreeNode right = buildTree(rightPre, rightInorder);

    root.left = left;
    root.right = right;

    return root;
}

Leetcode 106 由中序、後序構建樹

public TreeNode buildTree(int[] inorder, int[] postorder) {
    if(inorder.length == 0 || postorder.length == 0){
        return null;
    }

    int len = postorder.length;
    TreeNode root = new TreeNode(postorder[len - 1]);

    int inorderPos = 0;

    for(; inorderPos < len; inorderPos++){
        if(inorder[inorderPos] == root.val){
            break;
        }
    }

    int leftLength = inorderPos;
    int rightLength = len - inorderPos - 1;

    int[] leftInorder = new int[leftLength];
    int[] leftPost = new int[leftLength];

    int[] rightInorder = new int[rightLength];
    int[] rightPost = new int[rightLength];

    for(int i = 0; i < leftLength; i++){
        leftInorder[i] = inorder[i];
        leftPost[i] = postorder[i];
    }

    for(int i = 0; i < rightLength; i++){
        rightInorder[i] = inorder[inorderPos + 1 + i];
        rightPost[i] = postorder[leftLength + i];
    }

    TreeNode left = buildTree(leftInorder, leftPost);
    TreeNode right = buildTree(rightInorder, rightPost);

    root.left = left;
    root.right = right;

    return root;

}

 leetcode 124

思路:
分治:對於每個結點來講,須要計算,當前值+左結點+右結點 與 最大值的比較,同時,左結點與右結點的值經過遞歸獲得,所以,遞歸的返回值應是一條路徑的和post

public class Solution{
  int maxNum = Integer.MIN_VALUE;
  public int maxPathSum(TreeNode root){

      if(root == null){
        return 0;
      }
      count(root);
      return maxNum;
  }

  public int count(TreeNode root){
    int lval = Integer.MIN_VALUE, rval = Integer.MIN_VALUE;
    int val = root.val;

    if(root.left != null){
      lval = count(root.left);
    }

    if(root.right != null){
      rval = count(root.right);
    }

    val = val + Math.max(lval, 0) + Math.max(rval, 0);

    if(val > maxNum){
      maxNum = val;
    }

    return root.val + Math.max(Math.max(lval, rval), 0);
  }  
}

最小深度與最大深度

leetcode 111 最小深度

  • 遞歸法:
    思路:ui

退出條件指針

    1. root == null,直接返回0,可是!若是root.left或root.right其中一個爲null,不能退出遞歸,兩種解決方法
      方法一:使用新的遞歸函數規避code

      public int minDepth(TreeNode root){
        if(root == null){
          return 0;
        }
        return getMin(root);
      }
      public int getMin(TreeNode root){
        //規避左右子樹某一個爲null
        if(root == null){
          return Integer.MAX_VALUE;//排除此條路徑
        }
      
        if(root.left == null && root.right == null){
          return 1;
        }
        int left = Integer.MAX_VALUE;
        int right = Integer.MAX_VALUE;
      
        if(root.left != null){
          left = getMin(root.left);
        }
        if(root.right != null){
          right = getMin(root.right);
        }
      
        return Math.min(left, right) + 1;
      }

    方法二:給當前方法打補丁遞歸

    public int minDepth(TreeNode root) {
          if(root == null){
            return 0;
          }
    
          if(root.left == null && root.right == null){
            return 1;
          }
    
          if(root.left == null){
              return minDepth(root.right) + 1;
          }else if(root.right == null){
              return minDepth(root.left) + 1;
          }else{
              return Math.min(minDepth(root.left), minDepth(root.right)) + 1;
          }
    }
    1. root.left == null && root.right == null 說明爲葉子結點,返回1leetcode

    2. 當前層數加 左右子樹的最小深度get

    • 迭代法
      思路:層級遍歷,一旦在當前層發現葉子結點,返回層數io

    public int minDepth(TreeNode root){
        if(root == null){
          return 0;
        }
        if(root.left == null && root.right == null){
          return 1;
        }
    
        int depth = 0;
        int curLevelNodes = 1;
        int nextLevelNodes = 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
    
        while(!queue.isEmpty()){
          TreeNode cur = queue.poll();
          curLevelNodes--;
    
          if(cur.left == null && cur.right == null){
            return depth + 1;
          }
    
          if(cur.left != null){
            queue.add(cur.left);
            nextLevelNodes++;
          }
    
          if(cur.right != null){
            queue.add(cur.right);
            nextLevelNodes++;
          }
    
          if(curLevelNodes == 0){
            depth++;
            curLevelNodes = nextLevelNodes;
            nextLevelNodes = 0;
          }
        }
    
        return depth;
      }

    leetcode 104 最大深度

    • 遞歸法
      思路:遞歸時邏輯是一向的

    public int getMaxDepth(TreeNode root){
        if(root == null){
          return 0;
        }
    
        return Math.max(getMaxDepth(root.left), getMaxDepth(root.right)) + 1;
      }
    • 迭代法
      思路:層級遍歷求最大深度

    public int maxDepth(TreeNode root){
        if(root == null){
          return 0;
        }
        if(root.left == null && root.right == null){
          return 1;
        }
    
        int depth = 0;
        int curLevelNodes = 1;
        int nextLevelNodes = 0;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
    
        while(!queue.isEmpty()){
          TreeNode cur = queue.poll();
          curLevelNodes--;
    
          if(cur.left != null){
            queue.add(cur.left);
            nextLevelNodes++;
          }
    
          if(cur.right != null){
            queue.add(cur.right);
            nextLevelNodes++;
          }
    
          if(curLevelNodes == 0){
            depth++;
            curLevelNodes = nextLevelNodes;
            nextLevelNodes = 0;
          }
        }
    
        return depth;
      }

    leetcode 110 樹是否平衡

    樹平衡要求對全部結點來講,其左右子樹的深度差不超過1

    public boolean isBalanced(TreeNode root){
      if(root == null){
        return true;
      }
    
      int leftDepth = getMaxDepth(root.left);
      int rightDepth = getMaxDepth(root.right);
    
      if(Math.abs(leftDepth - rightDepth) > 1){
        return false;
      }
    
      return isBalanced(root.left) && isBalanced(root.right);
    }

    leetcode 100 判斷兩棵樹是否相同

    分析:樹的相同,首先結構相同,其次結點值相同
    兩種判斷結構是否相同的寫法,邏輯同樣
    方法一

    public boolean isSame(TreeNode r1, TreeNode r2){
        if(r1 == null && r2 == null){
          return true;
        }
        if(r1 == null || r2 == null){
          return false;
        }
        //else 結構相同
      }

    方法二

    public boolean isSame(TreeNode r1, TreeNode r2){
        if(r1 == null){
          return r2 == null;
        }
    
        if(r2 == null){
          return false;
        }
        //else 結構相同
      }

    完整邏輯

    public boolean isSame(TreeNode r1, TreeNode r2){
        if(r1 == null){
          return r2 == null;
        }
    
        if(r2 == null){
          return false;
        }
    
        return r1.val == r2.val && isSame(r1.left, r2.left) && isSame(r1.right, r2.right);
      }

    leetcode 101 判斷對稱

    左右子樹,結構相同,對稱位置值相同

    public boolean isSymmetric(TreeNode root) {
      if(root == null){
        return true;
      }
      return help(root.left, root.right);
    }
    
    public boolean help(TreeNode p, TreeNode q){
      if(p == null){
        return q == null;
      }
      if(q == null){
        return false;
      }
    
      return p.val == q.val && help(p.left, q.right) && help(p.right, q.left);
    }

    leetcode 98 判斷二叉搜索樹

    • 迭代法
      思路:中序遍歷 前一個結點值小於後面的結點值

    public boolean isValidBST(TreeNode root){
      if(root == null){
        return true;
      }
    
      Stack<TreeNode> stack = new Stack<>();
      TreeNode cur = root;
    
      TreeNode preCur = null;
      while(true){
        while(cur != null){
            stack.push(cur);
            cur = cur.left;
          }
    
          if(stack.isEmpty()){
            break;
          }
    
          cur = stack.pop();
    
          if(preCur != null){
            if(preCur.val >= cur.val){
              return false;
            }
          }
          preCur = cur;
          cur = cur.right;
      }  
      return true;
    }
    • 遞歸法
      思路:一樣是中序遍歷

    思考 pre結點在哪賦值,賦值前如何處理

    TreeNode pre = null;
        public boolean isValidBST(TreeNode root) {
            if(root == null){
              return true;
            }
    
            if(root.left == null && root.right == null){
                return true;
            }
    
            return help(root);
        }
    
        public boolean help(TreeNode root){
            if(root == null){
                return true;
            }
    
            boolean left = help(root.left);
            if(pre != null && pre.val >= root.val){
                return false;
            }
            pre = root;
            boolean right = help(root.right);
            return left && right;
        }

    鏈表與樹

    leetcode 114 二叉樹轉鏈表

    思路:斷開每個結點,從用一個指針遞歸地向下指,每次都只更新右結點,遞歸順序爲先左子樹,後右子樹

    TreeNode pointer = new TreeNode(-1);
      public void flatten(TreeNode root){
        if(root == null){
          return;
        }
        TreeNode left = root.left;
        TreeNode right = root.right;
        root.left = null;
        root.right = null;
        pointer.right = root;
        pointer = root;
    
        flatten(root.left);
        flatten(root.right);
      }

    鏈表轉二叉樹

    O(nlogn)解法

    public TreeNode sortedListToBST(ListNode head){
           if(head == null){
             return null;
           }
           if(head.next == null){
               return new TreeNode(head.val);
           }
           int length = 0;
           ListNode cur = head;
           while(cur != null){
             cur = cur.next;
             length++;
           }
           return help(head, length);
     }
       public TreeNode help(ListNode head, int length){
         if(length == 0){
           return null;
         }
    
         ListNode now = head;
         for(int i = 0; i < (length - 1) >> 1; i++){
           now = now.next;
         }
         TreeNode root = new TreeNode(now.val);
    
         TreeNode left = help(head, (length - 1) >> 1);
         TreeNode right = help(now.next, length >> 1);
    
         root.left = left;
         root.right = right;
    
         return root;
       }

    O(n)解法
    將鏈表先轉成數組

    leetcode 108 數組轉平衡二叉樹

    public TreeNode sortedArrayToBST(int[] nums) {
            if(nums.length == 0){
                return null;
            }
    
            if(nums.length == 1){
                return new TreeNode(nums[0]);
            }
    
            int length = nums.length;
            int now = nums[(length - 1) >> 1];
            TreeNode root = new TreeNode(now);
            int leftLen = (length - 1) >> 1;
            int rightLen = length >> 1;
    
            int[] leftArr = new int[leftLen];
            int[] rightArr = new int[rightLen];
            System.arraycopy(nums, 0, leftArr, 0, leftLen);
            System.arraycopy(nums, leftLen + 1, rightArr, 0, rightLen);
    
            root.left = sortedArrayToBST(leftArr);
            root.right = sortedArrayToBST(rightArr);
    
            return root;
        }
    相關文章
    相關標籤/搜索