目次
173.二分探索木反復子
質問の意味:
BSTIterator
二分探索ツリー(BST) を順番に走査する反復子を表す二分探索ツリー反復子クラスを実装します。
BSTIterator(TreeNode root)
BSTIterator
クラスのオブジェクト を初期化します 。BST のルート ノードはroot
コンストラクターの一部として指定されます。ポインタは、BST に存在せず、BST のどの要素よりも小さい数値に初期化する必要があります。boolean hasNext()
ポインタの右側を通過する数値がある場合は returntrue
、そうでない場合は returnfalse
。int next()
ポインタを右に移動し、ポインタの位置の数値を返します。ポインタは BST に存在しない数値に初期化されるため、
next()
最初の呼び出しでは BST 内の最小の要素が返されることに注意してください。
next()
呼び出しは常に有効である、つまり、next()
呼び出し時に BST の順序トラバーサル内に少なくとも 1 つの次の番号があると想定できます 。
【入力サンプル】
["BSTIterator", "next", "next", "hasNext", "next", "hasNext", "next", "hasNext", "next", "hasNext"] [[[7, 3, 15, null、null、9、20]]、[]、[]、[]、[]、[]、[]、[]、[]、[]]
【出力サンプル】
[null、3、7、true、9、true、15、true、20、false]
問題解決のアイデア:
ツリーの順序どおりの走査を実行し、ノード情報を配列に格納し、クエリ操作を配列内で直接実行します。
class BSTIterator{
private int idx;
private List<Integer> arr;
public BSTIterator(TreeNode root){
idx = 0;
arr = new ArrayList<Integer>();
inOrder(root,arr);
}
public int next(){
return arr.get(idx++);
}
public boolean hasNext(){
return idx < arr.size();
}
private void inOrder(TreeNode node, List<Integer> arr){
if(node == null){
return;
}
inOrder(node.left,arr);
arr.add(node.val);
inOrder(node.right,arr);
}
}
/**
* 解法二,用栈,实时维护
class BSTIterator {
private TreeNode cur;
private Deque<TreeNode> stack;
public BSTIterator(TreeNode root) {
cur = root;
stack = new LinkedList<TreeNode>();
}
public int next() {
while(cur != null){
stack.push(cur);
cur = cur.left;
}
cur = stack.pop();
int ret = cur.val;
cur = cur.right;
return ret;
}
public boolean hasNext() {
return cur != null || !stack.isEmpty();
}
}
*/
タイム: 敗北 43.62%
メモリ: 83.64% 上回る
222.完全な二分木のノードの数
質問の意味:
完全なバイナリ ツリー のルート ノードが 与えられた場合
root
、ツリー内のノードの数を見つけます。完全な二分木 の定義は次のとおりです。 完全な二分木では、満たされていない可能性がある最下位のノードを除いて、各層のノード数が最大に達し、最下層のノードが集中します。レイヤーの左端の位置。最下層が th
h
層の場合、その層には1~ 2h
ノードが含まれます。上級:ツリーを走査してノードをカウントすることは、時間計算量が の
O(n)
単純なソリューションです。もっと高速なアルゴリズムを設計できますか?
[入力例] root=[1,2,3,4,5,6]
【出力例】6
問題解決のアイデア:
バイナリ ツリーの特性に従って、ルート ノードから開始して、左側のサブツリーの左端のブランチが通過する深さが、右のサブツリーの右端のブランチが通過する深さと等しいかどうかを最初に判断できます。 、これは完全な二分木であり、計算が簡単です。
そうでない場合、これは完全なバイナリ ツリーではないことを意味します。左の子と右の子をそれぞれ再帰します。再帰が特定の深さに達すると、完全なバイナリ ツリーである左の子または右の子が存在します。完全なバイナリ ツリーの状況に従って計算することもできます。
class Solution {
public int countNodes(TreeNode root) {
//满二叉树 2^高度 -1.(根节点的高度为0)
if(root == null) return 0;
TreeNode left = root.left;
TreeNode right = root.right;
int leftDepth =0,rightDepth = 0;
while(left != null){
left = left.left;
++leftDepth;
}
while(right != null){
right = right.right;
++rightDepth;
}
if(rightDepth == leftDepth){
return (2 << leftDepth) - 1;
}
//根节点记得要加上
return countNodes(root.left) + countNodes(root.right) + 1;
}
}
時間: 100.00% を達成
メモリ: 13.81% の差
199.二分木の右側面図
質問の意味:
二分木のルートノードが 与えられたとき
root
、自分がその右側に立っていると想像し、右側から見えるノードの値を上から順に返します。
【入力例】[1,2,3,null,5,null,4]
[出力サンプル][1,3,4]
問題解決のアイデア:
レベル トラバーサル、および各レイヤーの深度を記録します。マップを使用して深さレイヤーのノード値を保存します。レベル トラバーサルは左から右に行われるため、マップ内の key= Depth のときの値はこのレイヤーの右端である必要があります。ノード。
class Solution {
public List<Integer> rightSideView(TreeNode root) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
int max_depth = -1;
Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
Queue<Integer> depthQueue = new LinkedList<Integer>();
nodeQueue.add(root);
depthQueue.add(0);//一个存节点信息,一个第几个节点
while(!nodeQueue.isEmpty()){
TreeNode node = nodeQueue.remove();
int depth = depthQueue.remove();
if(node != null){
max_depth = Math.max(max_depth,depth);
map.put(depth,node.val);//第depth层的最右侧节点
nodeQueue.add(node.left);
nodeQueue.add(node.right);
depthQueue.add(depth+1);
depthQueue.add(depth+1);
}
}
List<Integer> right = new ArrayList<Integer>();
for(int depth = 0; depth <= max_depth; ++depth){
right.add(map.get(depth));
}
return right;
}
}
タイム: 81.37% を達成
メモリ: 5.58% 劣る
637. 二分木のレベル平均
質問の意味:
空ではないバイナリ ツリーのルート ノードを指定すると
root
、各レベルのノードの平均値を配列の形式で返します。実際の回答の 10% 以内の 回答が10-5
受け入れられる場合があります。
[入力例] root = [3,9,20,null,null,15,7]
[出力サンプル][3.00000,14.50000,11.00000]
問題解決のアイデア: 深さ優先検索では、2 つのリストを使用して、各層のノードの数とノード値の合計をカウントします。
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Integer> nums = new ArrayList<Integer>();
List<Double> sums = new ArrayList<Double>();
List<Double> avgs = new ArrayList<Double>();
dfs(root,0,nums,sums);
int size = nums.size();
for(int i=0;i<size;++i){
avgs.add(sums.get(i)/nums.get(i));
}
return avgs;
}
public void dfs(TreeNode root, int level,List<Integer> nums,List<Double> sums){
if(root == null){
return;
}
if(level < sums.size()){
sums.set(level,sums.get(level) + root.val);
nums.set(level,nums.get(level)+1);
}else{
sums.add(1.0 * root.val);
nums.add(1);
}
dfs(root.left,level+1,nums,sums);
dfs(root.right,level+1,nums,sums);
}
}
時間: 100.00% を達成
メモリ: 82.36% 上回る
102.二分木のレベル順走査
質問の意味:
バイナリ ツリーのルート ノードを指定すると 、
root
そのノード値の レベル順の走査を返します 。(つまり、左から右にレイヤーごとにすべてのノードにアクセスします)。
[入力例] root = [3,9,20,null,null,15,7]
[出力サンプル][[3],[9,20],[15,7]]
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null) return res;
Queue<TreeNode> que = new LinkedList<TreeNode>();//存储节点
que.add(root);
while(!que.isEmpty()){
List<Integer> temp = new ArrayList<Integer>();//存储每一层的节点
int depthSize = que.size();//当前层有多少个节点
for(int i=1;i<=depthSize;++i){
TreeNode node = que.poll();
temp.add(node.val);
if(node.left!=null){
que.add(node.left);
}
if(node.right != null){
que.add(node.right);
}
}
res.add(temp);
}
return res;
}
}
タイム: 91.04% を達成
メモリ: 27.87% 劣る
103.二分木のジグザグレベルトラバース
質問の意味:
バイナリ ツリーのルート ノードを指定すると 、
root
そのノード値の ジグザグ レベル順序トラバーサルを返します 。(つまり、最初に次のレイヤーを左から右に移動し、次に右から左にというように、レイヤー間を交互に移動します)。
[入力例] root = [3,9,20,null,null,15,7]
[出力サンプル][[3],[20,9],[15,7]]
問題解決のアイデア: 質問 102 に基づいて、変数を追加して左から右か右から左かを決定し、キュー内で addLast と addFirst を使用して、さまざまな状況で要素を追加する順序を実装します。
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root == null) return res;
Queue<TreeNode> que = new LinkedList<TreeNode>();//存储节点
que.add(root);
boolean leftToRight = true;
while(!que.isEmpty()){
Deque<Integer> temp = new LinkedList<Integer>();//存储每一层的节点
int depthSize = que.size();//当前层有多少个节点
for(int i=1;i<=depthSize;++i){
TreeNode node = que.poll();
if(leftToRight){
temp.addLast(node.val);
}else{
temp.addFirst(node.val);
}
if(node.left!=null){
que.add(node.left);
}
if(node.right != null){
que.add(node.right);
}
}
res.add(new LinkedList<Integer>(temp));
leftToRight = !leftToRight;
}
return res;
}
}
タイム: 72.75% を達成
メモリ: 26.27% の差