面接の質問 04.09. 二分探索木列
配列を左から右にたどって、要素をツリーに連続的に挿入することによって、二分探索ツリーを徐々に生成できます。
さまざまなノードで構成される二分探索ツリー ルートが与えられた場合、このツリーを生成できるすべての可能な配列を出力します。
例 1:
输入: root = [2,1,3]
输出: [[2,1,3],[2,3,1]]
解释: 数组 [2,1,3]、[2,3,1] 均可以通过从左向右遍历元素插入树中形成以下二叉搜索树
2
/ \
1 3
例 2:
输入: root = [4,1,null,null,3,2]
输出: [[4,1,3,2]]
ヒント:
- 二分探索ツリー内のノードの数は [0, 1000] の範囲内です。
- 1 <= ノード値 <= 10^6
- このユースケースでは、要件を満たすアレイの数が 5000 を超えないようにします。
C++ コード
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<vector<int>> BSTSequences(TreeNode* root) {
if (root == nullptr) {
return {
{
}};
}
deque<TreeNode*> dq; // 双端队列可以两端插入和删除,便于处理回溯;queue只能在队列头部删除,队列尾部插入
dq.push_back(root);
dfs(dq);
return res;
}
void dfs(deque<TreeNode*>& dq) {
// 终止条件
if (dq.empty()) {
// 说明状态不会再扩展,path已经选择完了最后一个节点
res.push_back(path);
return;
}
// 遍历选择条件
for (unsigned int i = 0; i < dq.size(); ++i) {
// 作出选择(修改全局变量)
TreeNode* top = dq.front();
dq.pop_front();
path.push_back(top->val);
if (top->left) {
dq.push_back(top->left);
}
if (top->right) {
dq.push_back(top->right);
}
// 递归
dfs(dq);
// 回溯 (恢复全局变量)
if (top->left) {
dq.pop_back();
}
if (top->right) {
dq.pop_back();
}
dq.push_back(top); // 满足队列先进先出条件,不要使用push_front
path.pop_back();
}
}
private:
vector<int> path;
vector<vector<int>> res;
};
参考
- リコウ問題 1 の解決策 - 各ノードはその子孫の前にランク付けされる必要があります。
- リコウ問題の解決策 2 - C++ の方が DFS バックトラッキングを理解しやすい
- バックトラッキング、DFS、再帰の関係
- バックトラッキングと DFS は本質的に同じ考え方であり、両方とも検索アルゴリズムであり、両方とも再帰を使用して実装されます。バックトラッキング アルゴリズムは、考えられるすべての結果を検索し、基準を満たす結果を見つけようとすることで機能します。DFS アルゴリズムも再帰を利用して実装された検索アルゴリズムであり、後戻りアルゴリズムとは異なり、後戻りのない、つまりあるステップまで進んだ後は戻らない検索アルゴリズムです。
- 再帰とは、プログラムを作成するときに、部分問題がさらに分解する必要がなくなるまで、問題をより小さな部分問題に分割して問題を解決する方法であるプログラミングまたはプログラミング手法です。バックトラッキング アルゴリズムと DFS アルゴリズムは両方とも、再帰を通じて検索問題を解決します。
- したがって、バックトラッキング、DFS、再帰の間には密接な関係と相互依存関係があり、バックトラッキングと DFS アルゴリズムは両方とも再帰を使用して実装されており、再帰はバックトラッキングと DFS アルゴリズムの基礎であると言えます。
- 再帰とバックトラッキングの一般的な構造:
- バックトラッキング アルゴリズム テンプレート:
void backtrack(参数) {
if (终止条件) {
存储结果;
return;
}
for (选择:选择列表) {
做出选择;
backtrack(新参数);
撤销选择;
}
}
- バックトラッキング アルゴリズムでよく使用される質問:
- 8人の女王の問題
- 数独問題
- ブラケットの生成
- 完全順列問題
- 組み合わせ和問題
- 単語検索の質問
- サブセット問題
- 電話番号の文字の組み合わせの問題
- 分割回文文字列問題
- Nクイーン問題
- デキューとキューの違い:
キューは先入れ先出し (FIFO) データ構造であり、要素はキューの最後にのみ挿入でき、キューの先頭からは削除できます。Deque は両端のキューであり、要素はキューの両端から挿入または削除できます。キューは、タスクのスケジュール設定、メッセージ配信など、連続した操作が必要なシナリオに適しています。Deque は、スライディング ウィンドウやゲーム開発など、キューの両端での操作が必要なシナリオに適しています。 - deque の一般的に使用される関数:
- Push_front(): deque の前に要素を追加します。
- Push_back() : dequeの後に要素を追加します(キューのpush()と同じ機能)
- Pop_front() : deque の最初の要素を削除します (キューの Pop() と同じ機能)
- Pop_back(): deque の最後の要素を削除します。
- Front(): deque の最初の要素を返します (queue と同じ)
- back(): deque の最後の要素を返します (queue と同じ)
- size(): deque 内の要素の数を返します (queue と同じ)
- empty(): deque が空かどうかを確認します (queue と同じ)
- clear():両端キュー内のすべての要素を削除します