すべての質問は簡単なレベルです。
BSTのノード間の最短距離
質問[783]:ルート・ノードのルートでバイナリ検索ツリー(BST)が与えられると、ツリー内の任意の2つの異なるノードの値の間の最小の差を返します。
例
Input: root = [4,2,6,1,3,null,null]
Output: 1
Explanation: Note that root is a TreeNode object, not an array. The given tree [4,2,6,1,3,null,null] is represented by the following diagram:
4
/ \
2 6
/ \
1 3
while the minimum difference in this tree is 1, it occurs between node 1 and node 2, also between node 3 and node 2.
解決
トラバーサル順序どおり、だけトラバーサル一回。
class Solution
{
public:
int minDiffInBST(TreeNode *root)
{
return inorder2(root);
}
int inorder2(TreeNode *root)
{
bool first = true;
int diff = 0x7ffffff;
int pre = -1;
auto p = root;
stack<TreeNode *> s;
while (p != nullptr || !s.empty())
{
if (p != nullptr)
{
s.push(p);
p = p->left;
}
else
{
p = s.top(), s.pop();
if (first)
pre = p->val, first = false;
else
diff = min(diff, abs(p->val - pre)), pre = p->val;
p = p->right;
}
}
return diff;
}
int inorder(TreeNode *root)
{
vector<int> v;
auto p = root;
stack<TreeNode *> s;
while (p != nullptr || !s.empty())
{
if (p != nullptr)
{
s.push(p);
p = p->left;
}
else
{
p = s.top(), s.pop();
v.push_back(p->val);
p = p->right;
}
}
int diff = abs(v[1] - v[0]);
for (int i = 2; i < (int)v.size(); i++)
diff = min(diff, abs(v[i] - v[i - 1]));
return diff;
}
};
リーフと同様に木
質問[872]:バイナリツリーのすべての葉を考えてみましょう。左から右の順に、それらの葉の値は、リーフ値のシーケンスを形成します。その葉の値のシーケンスが同じである場合、2つのバイナリツリーは、葉と同様の考えられています。ヘッドノードと場合にのみ与えられた二つの木は、trueを返しますroot1
とroot2
葉に類似しています。
解決
トラバーサル順序どおり。
class Solution
{
public:
bool leafSimilar(TreeNode *root1, TreeNode *root2)
{
return inorder(root1) == inorder(root2);
}
vector<int> inorder(TreeNode *root)
{
vector<int> v;
auto p = root;
stack<TreeNode *> s;
while (!s.empty() || p != nullptr)
{
if (p != nullptr)
{
s.push(p);
p = p->left;
}
else
{
p = s.top(), s.pop();
if (p->left == nullptr && p->right == nullptr)
v.push_back(p->val);
p = p->right;
}
}
return v;
}
};
昇順検索ツリー
質問[897]:二分探索木を考えると、ツリー内の左端のノードが今ツリーのルートで、すべてのノードが左の子とだけ1右の子を持っていないようで、順番にツリーを並べ替えます。
例
Input: [5,3,6,2,4,null,8,1,null,null,null,7,9]
5
/ \
3 6
/ \ \
2 4 8
/ / \
1 7 9
Output: [1,null,2,null,3,null,4,null,5,null,6,null,7,null,8,null,9]
1
\
2
\
3
\
4
\
5
\
6
\
7
\
8
\
9
解決
TreeNode *increasingBST(TreeNode *root)
{
return inorder(root);
}
TreeNode *inorder(TreeNode *oldRoot)
{
TreeNode *newRoot = new TreeNode(-1);
auto t = newRoot;
auto p = oldRoot;
stack<TreeNode *> s;
while (p != nullptr || !s.empty())
{
if (p != nullptr)
s.push(p), p = p->left;
else
{
p = s.top(), s.pop();
t->right = new TreeNode(p->val);
t = t->right;
p = p->right;
}
}
return newRoot->right;
}
BSTの範囲和
質問[938]:バイナリサーチツリーのルートノードを考えると、L及びR(両端を含む)の間の値を持つすべてのノードの値の合計を返します。二分探索木は、一意の値を持つことが保証されています。
例
Input: root = [10,5,15,3,7,null,18], L = 7, R = 15
Output: 32
解決
三つのソリューション。
- INORDERトラバーサル
int inorder(TreeNode *root, int l, int r)
{
int sum = 0;
auto p = root;
stack<TreeNode *> s;
while (p != nullptr || !s.empty())
{
if (p)
s.push(p), p = p->left;
else
{
p = s.top(), s.pop();
if (l <= p->val && p->val <= r)
sum += p->val;
else if (p->val > r)
break;
p = p->right;
}
}
return sum;
}
- 再帰で検索
int sum = 0;
void helper(TreeNode *root, int l, int r)
{
if (root == nullptr) return;
if (root->val < l) helper(root->right, l, r);
else if (root->val > r) helper(root->left, l, r);
else
{
sum += root->val;
helper(root->left, l, r);
helper(root->right, l, r);
}
}
- 反復(スタック)で検索
int search(TreeNode *root, int l, int r)
{
int result = 0;
auto p = root;
stack<TreeNode *> s;
s.push(p);
while (!s.empty())
{
p = s.top(), s.pop();
if (p == nullptr)
continue;
if (l <= p->val && p->val <= r)
{
result += p->val;
s.push(p->right);
s.push(p->left);
}
else if (p->val < l)
s.push(p->right);
else if (p->val > r)
s.push(p->left);
}
return result;
}
バイナリツリーのいとこ
質問[993]:バイナリツリーで、ルートノードは、深さであり0
、各深さの子k
ノードは、深さですk+1
。バイナリツリーの2つのノードが、彼らは同じ深さを持っている場合はいとこですが、異なる親を持ちます。我々は、ユニークな値を持つ二分木のルートを与え、そして値であるx
とy
、ツリー内の2つの異なるノードの。戻りtrue
場合にのみ値に対応するノードの場合x
とはy
いとこです。
解決
レベル順トラバーサル。
class Solution
{
public:
bool isCousins(TreeNode *root, int x, int y)
{
if (root == nullptr)
return false;
queue<TreeNode *> q;
TreeNode *xparent = nullptr, *yparent = nullptr;
auto p = root;
q.emplace(p);
while (!q.empty())
{
queue<TreeNode *> nextlevel;
while (!q.empty())
{
p = q.front(), q.pop();
if (p->left)
{
nextlevel.emplace(p->left);
if (x == p->left->val)
xparent = p;
if (y == p->left->val)
yparent = p;
}
if (p->right)
{
nextlevel.emplace(p->right);
if (x == p->right->val)
xparent = p;
if (y == p->right->val)
yparent = p;
}
}
q = nextlevel;
// not found yet
if (xparent == nullptr && yparent == nullptr)
continue;
// not same level
if ((xparent == nullptr) ^ (yparent == nullptr))
return false;
// found at same level
return xparent != yparent;
}
// can not be here
return false;
}
};
ルートにリーフバイナリ数の和
質問[1022]バイナリツリーを考えると、各ノードは値を持っています0
か、1
。各ルート・ツー・リーフパスが最上位ビットで始まる2進数を表します。パスがある場合、例えば、0 -> 1 -> 1 -> 0 -> 1
これは、ツリー内のすべての葉については13であり、バイナリ01101を表すことができ、次いで、その葉へのルートからのパスで表される数値を考えます。これらの数字の合計を返します。
例
Input: [1,0,1,0,1,0,1]
Output: 22
Explanation: (100) + (101) + (110) + (111) = 4 + 5 + 6 + 7 = 22
解決
ビット演算とバックトラック法(実際には先行順走査)。使用するval = (val << 1) | p->val
パスを記録すること。
class Solution
{
public:
int sum = 0;
int sumRootToLeaf(TreeNode *root)
{
preorder(0, root);
return sum;
}
void preorder(int val, TreeNode *p)
{
if (p == nullptr)
return;
val = (val << 1) | p->val;
if (p->left == nullptr && p->right == nullptr)
sum += val;
preorder(val, p->left);
preorder(val, p->right);
}
};
面接の質問
BiNode LCCI
質問[17.12]:データ構造はTreeNode
二分木のために使用されるが、それはまた、(左がnullであり、右側のリスト内の次のノードである)単一のリンクリストを表すために使用することができます。(で実装バイナリ検索ツリーを変換する方法を実装TreeNode
単一リンクされたリストにします)。値は、順番に維持する必要があり、操作が(元のデータ構造に、である)場所で行われるべきです。変換した後、リンクリストのヘッドノードを返します。
例
Input: [4,2,5,1,3,null,6,0]
Output: [0,null,1,null,2,null,3,null,4,null,5,null,6]
解決
トラバーサル順序どおり。
TreeNode *convertBiNode(TreeNode *root)
{
TreeNode *newRoot = new TreeNode(-1);
auto t = newRoot;
auto p = root;
stack<TreeNode *> s;
while (!s.empty() || p != nullptr)
{
if (p)
{
s.emplace(p);
p = p->left;
}
else
{
p = s.top(), s.pop();
t->right = p, t = t->right;
p = p->right;
}
}
t = newRoot;
while (t)
t->left = nullptr, t = t->right;
return newRoot->right;
}