LeetCode 671 - Second Minimum Node In a Binary Tree


https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/description/
Given a non-empty special binary tree consisting of nodes with the non-negative value, where each node in this tree has exactly twoor zero sub-node. If the node has two sub-nodes, then this node's value is the smaller value among its two sub-nodes.
Given such a binary tree, you need to output the second minimum value in the set made of all the nodes' value in the whole tree.
If no such second minimum value exists, output -1 instead.
Example 1:
Input: 
    2
   / \
  2   5
     / \
    5   7

Output: 5
Explanation: The smallest value is 2, the second smallest value is 5.
Example 2:
Input: 
    2
   / \
  2   2

Output: -1
Explanation: The smallest value is 2, but there isn't any second smallest value.
X. https://leetcode.com/problems/second-minimum-node-in-a-binary-tree/discuss/107233/Java-4-lines
public int findSecondMinimumValue(TreeNode root) {
        if(root.left == null) return -1;
        
        int l = root.left.val == root.val ? findSecondMinimumValue(root.left) : root.left.val;
        int r = root.right.val == root.val ? findSecondMinimumValue(root.right) : root.right.val;
        
        return l == -1 || r == -1 ? Math.max(l, r) : Math.min(l, r);
    }
https://segmentfault.com/a/1190000017125308
    public int findSecondMinimumValue(TreeNode root) {
        if(root == null || root.left == null) return -1;
        
        int leftRes, rightRes;
        if (root.left.val == root.val) {
            leftRes = findSecondMinimumValue(root.left);
        } else {
            leftRes = root.left.val;
        }
        if (root.right.val == root.val) {
            rightRes = findSecondMinimumValue(root.right);
        } else {
            rightRes = root.right.val;
        }
        
        if (leftRes == -1 && rightRes == -1) return -1;
        else if (leftRes == -1) return rightRes;
        else if (rightRes == -1) return leftRes;
        else return Math.min(leftRes, rightRes);
    }
对于左结点和右结点, 如果它们的值都和父结点的值一样的话,继续递归左结点和右结点。
如果它们的值并不是都和父结点的值一样,那么哪个不一样,结果就取哪个的值。如果两个都不一样,那么取两者中较小的那个。
public int findSecondMinimumValue(TreeNode root) {
    if (root == null) {
        return -1;
    }
    if (root.left == null && root.right == null) {
        return -1;
    }
    
    int left = root.left.val;
    int right = root.right.val;
    
    // if value same as root value, need to find the next candidate
    if (root.left.val == root.val) {
        left = findSecondMinimumValue(root.left);
    }
    if (root.right.val == root.val) {
        right = findSecondMinimumValue(root.right);
    }
    
    if (left != -1 && right != -1) {
        return Math.min(left, right);
    } else if (left != -1) {
        return left;
    } else {
        return right;
    }
}
X. https://zxi.mytechroad.com/blog/leetcode/leetcode-671-second-minimum-node-in-a-binary-tree/
    // Return the second smallest number in the (sub-tree)
    // s1 is the smallest value
    int DFS(TreeNode* root, int s1) {
        if(!root) return -1;
        
        // If root's value is already grater than s1,
        // then all its children's value should be >= s1.
        // Thus root's value is the second smallest one.
        // No need to visit the
        if(root->val > s1) return root->val;
        
        int sl = DFS(root->left, s1);
        int sr = DFS(root->right, s1);
        
        if(sl == -1) return sr;
        if(sr == -1) return sl;
        
        // Return the smaller one among two subtrees
        return min(sl, sr);
    }
http://www.cnblogs.com/grandyang/p/7590156.html
这道题让我们找二叉树中的第二小的结点值,并且给该二叉树做了一些限制,比如对于任意一个结点,要么其没有子结点,要么就同时有两个子结点,而且父结点值是子结点值中较小的那个,当然两个子结点值可以相等。那么直接上暴力搜索呗,根据该树的附加条件可知,根结点一定是最小的结点值first,那么我们只要找出第二小的值second即可,初始化为整型的最大值。然后对根结点调用递归函数,将first和second当作参数传进去即可。在递归函数中,如果当前结点为空,直接返回,若当前结点孩值不等于first,说明其肯定比first要大,然后我们看其是否比second小,小的话就更新second,然后对当前结点的左右子结点分别调用递归函数即可,参见代码如下:
    int findSecondMinimumValue(TreeNode* root) {
        int first = root->val, second = INT_MAX;
        helper(root, first, second);
        return (second == first || second == INT_MAX) ? -1 : second;
    }
    void helper(TreeNode* node, int& first, int& second) {
        if (!node) return;
        if (node->val != first && node->val < second) {
            second = node->val;
        }
        helper(node->left, first, second);
        helper(node->right, first, second);
    }

下面这种方法也是用递归来做的,不过现在递归函数有了返回值,在递归函数中,还是先判断当前结点是否为空,为空直接返回-1。然后就是看当前结点是否等于first,不等于直接返回当前结点值。如果等于,我们对其左右子结点分别调用递归函数,分别得到left和right。如果left和right其中有一个为-1了,我们取其中的较大值;如果left和right都不为-1,我们取其中的较小值返回即可,参见代码如下:

    int findSecondMinimumValue(TreeNode* root) {
        return helper(root, root->val);
    }
    int helper(TreeNode* node, int first) {
        if (!node) return -1;
        if (node->val != first) return node->val;
        int left = helper(node->left, first), right = helper(node->right, first);
        return (left == -1 || right == -1) ? max(left, right) : min(left, right);
    }

下面这种递归方法更加简洁了,没有再使用专门的递归函数helper,而是对当前根结点判断其左子树是否存在,不存在就返回-1。题目中说了是非空树,所以根结点一定存在。然后我们比较如果左子结点值等于根结点值,我们则对其左子结点调用递归函数;否则left就等于其左子结点值。再比较如果右子结点值等于根结点值,则对其右子结点调用递归函数;否则right就等于其右子结点值。最后我们还是看如果left和right其中有一个为-1了,我们取其中的较大值;如果left和right都不为-1,我们取其中的较小值返回即可,参见代码如下:
    int findSecondMinimumValue(TreeNode* root) {
        if (!root->left) return -1;
        int left = (root->left->val == root->val) ? findSecondMinimumValue(root->left) : root->left->val;
        int right = (root->right->val == root->val) ? findSecondMinimumValue(root->right) : root->right->val;
        return (left == -1 || right == -1) ? max(left, right) : min(left, right);
    }
复制代码

整了三种递归的解法,来看一种迭代的解法吧,用的是层序遍历,但还是用的解法一种的不停更新second的方法,参见代码如下:

    int findSecondMinimumValue(TreeNode* root) {
        int first = root->val, second = INT_MAX;
        queue<TreeNode*> q{{root}};
        while (!q.empty()) {
            auto t = q.front(); q.pop();
            if (t->val != first && t->val < second) {
                second = t->val;
            }
            if (t->left) q.push(t->left);
            if (t->right) q.push(t->right);
        }
        return (second == first || second == INT_MAX) ? -1 : second;
    }


Let \text{min1 = root.val}. When traversing the tree at some node, \text{node}, if node.val > min1, we know all values in the subtree at \text{node} are at least \text{node.val}, so there cannot be a better candidate for the second minimum in this subtree. Thus, we do not need to search this subtree.
Also, as we only care about the second minimum \text{ans}, we do not need to record any values that are larger than our current candidate for the second minimum, so unlike Approach #1 we can skip maintaining a Set of values(uniques) entirely.
  • Time Complexity: O(N), where N is the total number of nodes in the given tree. We visit each node at most once.
  • Space Complexity: O(N). The information stored in \text{ans} and \text{min1} is O(1), but our depth-first search may store up to O(h) = O(N) information in the call stack, where h is the height of the tree.
  int min1;
  long ans = Long.MAX_VALUE;

  public void dfs(TreeNode root) {
    if (root != null) {
      if (min1 < root.val && root.val < ans) {
        ans = root.val;
      } else if (min1 == root.val) {
        dfs(root.left);
        dfs(root.right);
      }
    }
  }

  public int findSecondMinimumValue(TreeNode root) {
    min1 = root.val;
    dfs(root);
    return ans < Long.MAX_VALUE ? (int) ans : -1;

  }


  • Time Complexity: O(N), where N is the total number of nodes in the given tree. We visit each node exactly once, and scan through the O(N) values in unique once.
  • Space Complexity: O(N), the information stored in uniques.
  public void dfs(TreeNode root, Set<Integer> uniques) {
    if (root != null) {
      uniques.add(root.val);
      dfs(root.left, uniques);
      dfs(root.right, uniques);
    }
  }

  public int findSecondMinimumValue(TreeNode root) {
    Set<Integer> uniques = new HashSet<Integer>();
    dfs(root, uniques);

    int min1 = root.val;
    long ans = Long.MAX_VALUE;
    for (int v : uniques) {
      if (min1 < v && v < ans)
        ans = v;
    }
    return ans < Long.MAX_VALUE ? (int) ans : -1;

  }


Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts