1017 Queueing at Bank (25分)模擬:關於事務排隊處理
阿新 • • 發佈:2020-08-08
題解
方法一:
對於二叉搜尋樹,如果進行中序遍歷,那麼得到的序列是有序的,如果有兩個節點交換了,那麼就是無序的,我們只需要找出這兩個節點所在的位置然後交換值就好了。
先來看看交換兩個值會發生什麼。對於遞增序列a=[1,2,3,4,5]
- 如果交換不相鄰的數字,例如swap(a[1],a[3]),那麼a=[1,4,3,2,5],此時a[1]>a[2]&&a[2]>a[3],存在兩個非遞增序列。
- 如果交換相鄰的數字,例如swap(a[1],a[2]),那麼a=[1,3,2,4,5],此時a[1]>a[2],只存在一個非遞增序列。
程式碼
首先講一下pair的用法
pair<T,U> p1;
p1.first=value1;
p1.second=value2;
pair<T,U> p2(value1,value2);
pair<int,int> p3=make_pair(value1,value2);
//pair作為函式返回值
pair<int,int> function(int x,int y){
//注意是大括號
return {x,y};
}
程式碼
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: //中序遍歷,把中序遍歷的序列存入nums陣列中 void inorder(TreeNode* root,vector<int>& nums){ if(root==nullptr) return; inorder(root->left,nums); nums.push_back(root->val); inorder(root->right,nums); } //返回中序遍歷陣列中應該交換的兩個值(x,y) pair<int,int>findTwoSwapped(vector<int>& nums){ int n=nums.size(); int x=-1,y=-1; for(int i=0;i<n-1;++i){ //如果存在逆序對 if(nums[i]>nums[i+1]){ y=nums[i+1]; //如果x==-1,那麼x還沒有找到,否則若x!=-1,說明已經找到正確的x,此時(x,y)已經找到,退出就好 if(x==-1) x=nums[i]; else break; } } return {x,y}; } //在樹中swap(x,y),其中count用來記錄修改的次數,應該修改兩次,即count=2 void recover(TreeNode* root,int count,int x,int y){ if(root){ if(root->val==x||root->val==y){ //如果當前節點的值為x,那麼另它為y,否則若當前節點的值為y,那麼另它為x root->val=root->val==x?y:x; //如果count==0說明x和y已經修改完畢(修改了兩次) if(--count==0) return; } recover(root->left,count,x,y); recover(root->right,count,x,y); } } void recoverTree(TreeNode* root) { vector<int> nums; inorder(root,nums); pair<int,int> swapped=findTwoSwapped(nums); recover(root,2,swapped.first,swapped.second); } };
方法二:
通過非遞迴的中序遍歷找出(x,y),設定一個指標pred指向當前節點的root的前驅,如果pred->val>root->val,說明x=pred,x此時就找到了,繼續按相同的方法找y即可。
最後swap(x->val,y->val)
首先回顧一下中序遍歷的兩種非遞迴寫法:
第一種
void InOrder(TreeNode *root){ //空樹 if(!root) return; TreeNode* p=root; stack<TreeNode> s; //當p為root時,s為空 while(!s.empty()||p){ //一直遍歷到最左邊的節點 while(p){ s.push(p); p=p->left; } //此時p==nullptr,可以訪問p的父節點以及右孩子了 if(!s.empty()){ p=s.top(); s.pop(); visit(p); p=p->right; } } }
第二種
void InOrder2(TreeNode* root){
//空樹
if (!root)
return;
//樹非空
TreeNode* p = root;
stack<TreeNode*> s;
while (!s.empty() || p){
if (p){
s.push(p);
p = p->left;
}
else{
p = s.top();
s.pop();
visit(p);
p = p->right;
}
}
程式碼
利用第一種中序遍歷非遞迴寫法
class Solution {
public:
void recoverTree(TreeNode* root){
stack<TreeNode*> s;
TreeNode* x=nullptr;
TreeNode* y=nullptr;
TreeNode* pred=nullptr;
TreeNode* p=root;
while(!s.empty()||p){
while(p){
s.push(p);
p=p->left;
}
if(!s.empty()){
p=s.top();
s.pop();
if(pred&&p->val<pred->val){
y=p;
if(x==nullptr)
x=pred;
else break;
}
pred=p;
p=p->right;
}
}
swap(x->val,y->val);
}
};
利用第二種非遞迴中序遍歷寫法
class Solution {
public:
void recoverTree(TreeNode* root){
stack<TreeNode*> s;
TreeNode* x=nullptr;
TreeNode* y=nullptr;
TreeNode* pred=nullptr;
TreeNode* p=root;
while(!s.empty()||p){
if(p){
s.push(p);
p=p->left;
}
else{
p=s.top();
s.pop();
if(pred&&p->val<pred->val){
y=p;
if(x==nullptr)
x=pred;
else break;
}
pred=p;
p=p->right;
}
}
swap(x->val,y->val);
}
};
題目連結(https://leetcode-cn.com/problems/recover-binary-search-tree/)