バイナリ検索ツリーの最も近い共通の祖先バイナリ検索ツリーを指定すると、ツリー内の指定された2つのノードの最も近い共通の祖先を見つけます。
非常に単純な問題、再帰的な解決策:二分探索ツリーの場合、左サブツリー<ルート<右サブツリーでは、2つのノードが両側または同じ側にあるかどうかを判断できます。両側にある場合、ルートは最も近い共通の祖先です。それ以外の場合は、検索を続行します
/**
* 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:
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root->val == p->val || root->val == q->val)
{
return root;
}
if ((root->val > p->val && root->val < q->val)
|| (root->val < p->val && root->val > q->val))
{
return root;
}
if (root->val > p->val && root->val > q->val)
{
return lowestCommonAncestor(root->left, p, q);
}
else
{
return lowestCommonAncestor(root->right, p, q);
}
}
};
バイナリツリーの最も近い共通の祖先バイナリツリーが与えられた場合、ツリー内の指定された2つのノードの最も近い共通の祖先を見つけます。
バイナリサーチツリーの機能がないため、この質問は前の質問に比べて少し面倒です。したがって、再帰を行う場合は、下から開始する必要があり、特定のルートの左側のサブツリーと右側のサブツリーにノードがあることを確認すると、ルートノードが返されます。それ以外の場合、2つのノードの1つは共通の祖先でなければなりません。
class Solution {
public:
TreeNode* ans;
bool dfs(TreeNode* root, TreeNode* p, TreeNode* q) {
if (root == nullptr) return false;
bool lson = dfs(root->left, p, q);
bool rson = dfs(root->right, p, q);
if ((lson && rson) || ((root->val == p->val || root->val == q->val) && (lson || rson))) {
ans = root;
}
return lson || rson || (root->val == p->val || root->val == q->val);
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
dfs(root, p, q);
return ans;
}
};
別のアプローチは、各ノードの親ノードを記録し、2つのノードの共通ルートノードを見つけることです
class Solution {
public:
unordered_map<int, TreeNode*> fa;
unordered_map<int, bool> vis;
void dfs(TreeNode* root){
if (root->left != nullptr) {
fa[root->left->val] = root;
dfs(root->left);
}
if (root->right != nullptr) {
fa[root->right->val] = root;
dfs(root->right);
}
}
TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) {
fa[root->val] = nullptr;
dfs(root);
while (p != nullptr) {
vis[p->val] = true;
p = fa[p->val];
}
while (q != nullptr) {
if (vis[q->val]) return q;
q = fa[q->val];
}
return nullptr;
}
};
- リンクリスト内のノードの削除リンクリスト内の
特定の(終了していない)ノードを削除する関数を記述してください。削除する必要のあるノードのみが表示されます。
この質問の興味深い部分は、単一リンクリストは前のノードがノードを削除する方法を知らないということです。メソッドは、現在のノードを次のノードに割り当て、次のノードを削除することです。
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
void deleteNode(ListNode* node) {
if (node == NULL)
return;
if (node->next == NULL)
{
node = NULL;
return;
}
ListNode *tmp = node->next;
node->val = node->next->val;
node->next = node->next->next;
delete tmp;
return;
}
};
- それ以外の配列の積は
、長さnの整数配列numを与えます。ここで、n> 1は、出力配列の出力を返します。ここで、output [i]は、nums [i]を除くnumsの残りの要素の積に等しくなります。
この問題の解決策は、除算を使用できないことを制限するので、考えを変えることができます。2つの配列を使用して、左側の要素の積と右側の要素の積を現在の位置に格納し、その2つを乗算します。さらに単純化することができます。出力配列を使用して最初に左の要素を格納し、次に動的に右の要素を取得して、割り当てを直接乗算します。
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int length = nums.size();
vector<int> answer(length);
// answer[i] 表示索引 i 左侧所有元素的乘积
// 因为索引为 '0' 的元素左侧没有元素, 所以 answer[0] = 1
answer[0] = 1;
for (int i = 1; i < length; i++) {
answer[i] = nums[i - 1] * answer[i - 1];
}
// R 为右侧所有元素的乘积
// 刚开始右边没有元素,所以 R = 1
int R = 1;
for (int i = length - 1; i >= 0; i--) {
// 对于索引 i,左边的乘积为 answer[i],右边的乘积为 R
answer[i] = answer[i] * R;
// R 需要包含右边所有的乘积,所以计算下一个结果时需要将当前值乘到 R 上
R *= nums[i];
}
return answer;
}
};
- スライディングウィンドウの最大値
配列numsを指定すると、サイズkのスライディングウィンドウは、配列の左端から配列の右端に移動します。スライディングウィンドウでのみk番号を表示できます。スライディングウィンドウは、一度に1つの位置だけ右に移動します。
スライディングウィンドウの最大値を返します。
キューを使用してウィンドウを保存します。変数のフロントエンド(つまり、window.front())は、このトラバーサルの最大値の添え字です。新しい数値に遭遇すると、新しいアイテムをダブルアイテムキューの最後に追加します(またこれはwindow.back())の比較です。最後が新しい数よりも小さい場合、キューの最後が新しい数よりも大きくなるか、キューが空になるまで、最後は捨てられます。このアプローチは、スタックをブラケットマッチングに使用するようなものです。
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
if (k == 0) return {
};
vector<int> res;
deque<size_t> window;
/*Init K integers in the list*/
for (size_t i = 0; i < k; i++) {
while (!window.empty() && nums[i] > nums[window.back()]) {
window.pop_back();
}
window.push_back(i);
}
res.push_back(nums[window.front()]);
/*End of initialization*/
for (size_t i = k; i < nums.size(); i++) {
if (!window.empty() && window.front() <= i - k) {
window.pop_front();
}
while (!window.empty() && nums[i] > nums[window.back()]) {
window.pop_back();
}
window.push_back(i);
res.push_back(nums[window.front()]);
}
return res;
}
};
- 2次元マトリックスの検索2
mxnマトリックスマトリックスでターゲット値targetを検索するための効率的なアルゴリズムを記述します。行列には次の特性があります。
各行の要素は左から右に昇順で配置されます。
各列の要素は、上から下に昇順で配置されます。
この質問は典型的な二分探索ですが、二分探索に加えてソートされているため、対角線の原則によっても完了することができます。右上隅または左下隅から始めて、サイズ規則に従って行と列を移動して、境界が見つかるか、範囲外になります。
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
if(matrix.size() == 0||matrix[0].size() == 0)
{
return false;
}
int curx = matrix.size()-1,cury = 0;
while(curx >= 0 &&cury < matrix[0].size())
{
if(target > matrix[curx][cury])
{
cury++;
}
else if(target < matrix[curx][cury])
{
curx--;
}
else
{
return true;
}
}
return false;
}
};
- 演算式の優先順位を設計する
数値と演算子を含む文字列を指定して、式に括弧を追加し、演算の優先順位を変更してさまざまな結果を見つけます。すべての可能な組み合わせの結果を与える必要があります。有効な演算子には、+、-、および*が含まれます。
この質問では、分割統治アルゴリズムを使用して、式を偶然で区切られた部分に分解し、さまざまなソリューションを順番に見つけることができます。別のアプローチは、それを動的プログラミングソリューションとして扱うことです。すべての数値用とすべての演算子用の2つのリストを使用します。dp [i] [j]は、i番目からj番目の数値(0から数えます)の範囲の式のすべての解を表します。
class Solution {
public:
vector<int> diffWaysToCompute(string input) {
int index = 0;
int num = 0;
while(index < input.size() && isdigit(input[index]))
num = num * 10 + input[index++] - '0';
if(index == input.size()){
hash[input] = {
num};
return {
num};
}
vector<int> ans;
for(int i = 0; i < input.size(); i++){
if(isOp(input[i])){
string s1 = input.substr(0,i);
string s2 = input.substr(i);
vector<int> result1, result2;
if(!hash.count(s1))
result1 = diffWaysToCompute(input.substr(0,i));
else
result1 = hash[s1];
if(!hash.count(s2))
result2 = diffWaysToCompute(input.substr(i+1));
else
result2 = hash[s2];
for(int r1 : result1){
for(int r2 : result2){
ans.push_back(calculate(r1,input[i],r2));
}
}
}
}
hash[input] = ans;
return ans;
}
bool isOp(const char& c){
return c == '+' || c == '-' || c == '*';
}
int calculate(const int& num1, const char& op, const int& num2){
if(op == '+')
return num1 + num2;
else if(op == '-')
return num1 - num2;
else
return num1 * num2;
}
private:
unordered_map<string,vector<int>> hash;
};