菜🐔的學習之路java
掘金首頁node
給定一個非空特殊的二叉樹,每一個節點都是正數,而且每一個節點的子節點數量只能爲 2 或 0。若是一個節點有兩個子節點的話,那麼該節點的值等於兩個子節點中較小的一
個。
更正式地說,root.val = min(root.left.val, root.right.val) 總成立。
給出這樣的一個二叉樹,你須要輸出全部節點中的第二小的值。若是第二小的值不存在的話,輸出 -1 。
示例 1:
輸入:root = [2,2,5,null,null,5,7]
輸出:5
解釋:最小的值是 2 ,第二小的值是 5 。
示例 2:
輸入:root = [2,2,2]
輸出:-1
解釋:最小的值是 2, 可是不存在第二小的值。
提示:
樹中節點數目在範圍 [1, 25] 內
1 <= Node.val <= 231 - 1
對於樹中每一個節點 root.val == min(root.left.val, root.right.val)
Related Topics 樹 深度優先搜索 二叉樹
👍 159 👎 0
複製代碼
leetcode題目連接git
代碼連接github
思路一:DFSmarkdown
public int findSecondMinimumValue(TreeNode root) {
//corner case
PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>(new Comparator<Integer>() {
//小根堆
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2) return 1;
return o1.equals(o2) ? 0 : -1;
}
});
dfs(root, priorityQueue);
if (priorityQueue.size() >= 2) {
int min = priorityQueue.poll();
while (priorityQueue.peek()!=null){
if (priorityQueue.peek()>min){
return priorityQueue.poll();
}else{
priorityQueue.poll();
}
}
}
return -1;
}
private void dfs(TreeNode root, PriorityQueue<Integer> queue) {
if (root == null) {
return;
}
queue.add(root.val);
dfs(root.left, queue);
dfs(root.right, queue);
}
複製代碼
時間複雜度O(n)app
set寫法ide
private void dfs(TreeNode root, Set<Integer> queue) {
if (root == null) {
return;
}
queue.add(root.val);
dfs(root.left, queue);
dfs(root.right, queue);
}
public int findSecondMinimumValue(TreeNode root) {
//corner case
Set<Integer> set = new TreeSet<>(new Comparator<Integer>() {
//小根堆
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2) return 1;
return o1.equals(o2) ? 0 : -1;
}
});
dfs(root, set);
if (set.size() >= 2) {
int i = 0;
for (int num:set
) {
if (i == 1){
return num;
}else{
i++;
}
}
}
return -1;
}
複製代碼
時間複雜度O(n)oop
思路二:dfs+剪枝學習
public int findSecondMinimumValue(TreeNode root) {
//corner case
if (root.left == null){
return -1;
}
Set<Integer> set = new TreeSet<>(new Comparator<Integer>() {
//小根堆
@Override
public int compare(Integer o1, Integer o2) {
if (o1 > o2) return 1;
return o1.equals(o2) ? 0 : -1;
}
});
set.add(root.left.val);
set.add(root.right.val);
if (root.left.val == root.val) {
dfs3(root.left, set);
}
if (root.right.val == root.val) {
dfs3(root.right, set);
}
if (set.size() >= 2) {
int i = 0;
for (int num : set
) {
if (i == 1) {
return num;
} else {
i++;
}
}
}
return -1;
}
private void dfs3(TreeNode root, Set<Integer> set) {
if (root == null) {
return;
}
if (root.left == null) {
return;
}
set.add(root.left.val);
set.add(root.right.val);
if (root.left.val == root.val) {
dfs3(root.left, set);
}
if (root.right.val == root.val) {
dfs3(root.right, set);
}
}
複製代碼
時間複雜度O(n)優化
思路三:剪枝的進一步優化
其實以前解題時裏想到過這種思路
可是仍是沒有抓住重點就沒繼續往下思考
這種思路的依靠的條件有兩個
這樣的邏輯也就保證了ans只會在遇到了比最小值大的節點的時纔會更新
同時ans更新後沒必要再向下遍歷
剪枝的進一步優化-剪掉全部子節點
int ans = -1;
public int findSecondMinimumValue(TreeNode root) {
dfs(root, root.val);
return ans;
}
void dfs(TreeNode root, int cur) {
if (root == null) return ;
if (root.val != cur) {
if (ans == -1) ans = root.val;
else ans = Math.min(ans, root.val);
return ;
}
dfs(root.left, cur);
dfs(root.right, cur);
}
複製代碼
時間複雜度O(n)