2020/12/08----劍指offer打卡
21.棧的壓入、彈出序列
題目描述
輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能為該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)
解題思路:
構造一個輔助的棧,每次入棧之後與彈出棧的元素依次從序號為0的元素比較,相等則彈出,如果最後輔助棧為空,說明是一個彈出序列,否則不是。
程式碼實現:
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
int n=pushV.size();
int j=0;
stack<int>temp;
for(int i=0;i<n;i++){
temp.push(pushV[i]);
while(!temp.empty()&&temp.top()==popV[j]){
temp. pop();
j++;
}
}
return temp.empty();
}
};
22.從上到下列印二叉樹(樹的層序遍歷)
題目描述
從上往下打印出二叉樹的每個節點,同層節點從左至右列印。
解題思路:層次遍歷
- 初始化:一個佇列queue<TreeNode*> q, 將root節點入佇列q
- 如果佇列不空,做如下操作:
- 彈出佇列頭,儲存為node,將node的左右非空孩子加入佇列
- 做2,3步驟,知道佇列為空
如果不需要確定當前遍歷到了哪一層,模板如下:
void bfs() {
vis[ ] = 0;//標記陣列
queue<int> pq(start_val);
while (!pq.empty()) {
int cur = pq.front();
pq.pop();
for (遍歷cur所有的相鄰節點nex) {
if (nex節點有效 && vis[nex]==0){
vis[nex] = 1;//節點以訪問
pq.push(nex)
}
}
}
}
如果需要確定遍歷到哪一層,模板如下:
void bfs() {
int level = 0;//表示遍歷的層數
vis[] = 0; // or set
queue<int> pq(original_val);
while (!pq.empty()) {
int sz = pq.size();//記錄每一層的元數個數
while (sz--) {
int cur = pq.front(); pq.pop();
for (遍歷cur所有的相鄰節點nex) {
if (nex節點有效 && vis[nex] == 0) {
vis[nex] = 1;
pq.push(nex)
}
} // end for
} // end inner while
level++;
} // end outer while
}
程式碼實現:
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<int> PrintFromTopToBottom(TreeNode* root) {
queue<TreeNode*>que;
vector<int>ans;
if(root==nullptr) return ans;
que.push(root);
while(!que.empty()){
int sz=que.size();
while(sz--){
TreeNode *tmp=que.front();
que.pop();
ans.push_back(tmp->val);
if(tmp->left) que.push(tmp->left);
if(tmp->right) que.push(tmp->right);
}
}
return ans;
}
};
二叉搜尋樹的後序遍歷序列
題目描述
輸入一個整數陣列,判斷該陣列是不是某二叉搜尋樹的後序遍歷的結果。如果是則返回true,否則返回false。假設輸入的陣列的任意兩個數字都互不相同。
什麼是二叉搜尋樹:
二叉搜尋樹(Binary Search Tree),又名二叉排序樹(Binary Sort Tree)。
二叉搜尋樹是具有有以下性質的二叉樹:
(1)若左子樹不為空,則左子樹上所有節點的值均小於或等於它的根節點的值。
(2)若右子樹不為空,則右子樹上所有節點的值均大於或等於它的根節點值。 (3)左、右子樹也分別為二叉搜尋樹。
解題思路:
後序遍歷的最後一個數一定是根節點,而根據二叉搜尋樹的性質,左子樹的值一定小於根節點的值,右節點的值一定大於根節點的值,所以在陣列中找到比節點大的第一個數即可把原陣列分為左右兩部分。然後遞迴判斷左右子樹即可,注意遞迴的邊界條件為l大於等於r,l等於r會出錯,l大於R也可也執行。
**
程式碼實現:
class Solution {
public:
bool vf(vector<int> &sequence,int l,int r){
//邊界條件大於等於最為關鍵
if(l>=r) return true;
int i=0;
for(i=l;i<r;i++){
if(sequence[i]>sequence[r])
break;
}
for(int j=i;j<r;j++){//如果右邊小於根節點直接return false;
if(sequence[j]<sequence[r])
return false;
}
return vf(sequence,l,i-1)&&vf(sequence,i,r-1);
}
bool VerifySquenceOfBST(vector<int> sequence) {
if(sequence.size() == 0) return false;
return vf(sequence,0,sequence.size()-1);
}
};
題目描述
輸入一顆二叉樹的根節點和一個整數,按字典序打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
vector<vector<int>>ret;
vector<int>path;
void dfs(TreeNode *root,int sum,vector<int>&path,vector<vector<int>>&ret){
path.push_back(root->val);
if(sum==root->val&&!root->left&&!root->right){
ret.push_back(path);
}
if(root->left) dfs(root->left,sum-root->val,path,ret);
if(root->right) dfs(root->right,sum-root->val,path,ret);
path.pop_back();//回溯。重要
}
vector<vector<int> > FindPath(TreeNode* root,int expectNumber) {
if(root==nullptr) return ret;
dfs(root,expectNumber,path,ret);
return ret;
}
};
題目描述
輸入一個複雜連結串列(每個節點中有節點值,以及兩個指標,一個指向下一個節點,另一個特殊指標random指向一個隨機節點),請對此連結串列進行深拷貝,並返回拷貝後的頭結點。(注意,輸出結果中請不要返回引數中的節點引用,否則判題程式會直接返回空)
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
//第一步,複製每一個節點,如複製節點A得到A1,將A1插入到節點A的後面
void CloneNodes(RandomListNode *pHead){
RandomListNode *pNode=pHead;
while(pNode){
RandomListNode *pcloned=new RandomListNode(pNode->label);
pcloned->next=pNode->next;
pcloned->random=nullptr;
pNode->next=pcloned;
pNode=pcloned->next;
}
}
//第二步,為複製出來的節點新增random節點。A1->random=A->random->next;
void ConnectNodes(RandomListNode *pHead){
RandomListNode *pNode=pHead;
while(pNode){
RandomListNode *pcloned=pNode->next;
if(pNode->random!=nullptr){
pcloned->random=pNode->random->next;
}
pNode=pcloned->next;
}
}
//第三步:將連結串列拆分成原連結串列和複製後的連結串列
RandomListNode *Reconnect(RandomListNode *pHead){
RandomListNode *pclonedhead=pHead->next;
RandomListNode *pNode=pHead;
while(pNode){
RandomListNode *clonednode=pNode->next;
pNode->next=clonednode->next;
clonednode->next=clonednode->next==nullptr?nullptr:clonednode->next->next;
pNode=pNode->next;
}
return pclonedhead;
}
RandomListNode* Clone(RandomListNode* pHead)
{
if(!pHead) return nullptr;
CloneNodes(pHead);
ConnectNodes(pHead);
return Reconnect(pHead);
}
};
二叉樹中和為某一值的路徑
題目描述
輸入一顆二叉樹的根節點和一個整數,按字典序打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。
前置知識:
1.葉子節點表示:如果節點為root,那麼當前節點為葉子節點的必要條件為
二叉搜尋樹與雙向連結串列
題目描述
輸入一棵二叉搜尋樹,將該二叉搜尋樹轉換成一個排序的雙向連結串列。要求不能建立任何新的結點,只能調整樹中結點指標的指向。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
//**注意此處一定要用引用**
void inorder(TreeNode *pRoot,TreeNode *&pre){
if(pRoot==nullptr) return ;
inorder(pRoot->left,pre);
if(pre!=NULL){
pRoot->left=pre;
pre->right=pRoot;
}
pre=pRoot;
inorder(pRoot->right,pre);
}
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==nullptr) return nullptr;
TreeNode *pre=NULL;
inorder(pRootOfTree,pre);
while(pre->left!=NULL)
pre=pre->left;
return pre;
}
};