【計劃執行報告】Day8 LeetCode探索:二叉樹的典型操作實現【遞歸思想】

Day8 04-07 LeetCode探索:二叉樹的典型操作實現【遞歸思想】

今天是:

  1. 計劃執行的第8
  2. 學習二叉樹的一天
  3. 從計劃實現開始“浪”的時間最多的一天

從今天開始,非特殊情況不會把寫這些報告的時間記錄在atimelogger中(因爲寫報告時時間的記錄已經停止了),並且準備把明日的計劃也貼在最後

1.今日感想

  1. 機器學習的VAE聽不進去;
  2. 通過之前的學習以及今天的編程實踐對二叉樹的性質、典型操作(遞歸實現如DFS遍歷、BFS遍歷等等)有了更深刻的理解,但是目前還沒嘗試過用迭代方法解決這些問題;
  3. 掌握這些典型數據結構不僅僅是爲了程序競賽,更重要地是它們作爲一些機器學習算法的先修內容,有助於機器學習相關算法的理解,如決策樹、isomap等等

2.計劃執行報告

2.1近期計劃(03-31-04-12)

1.有所改動,貌似組內的大佬已經把所有工作承包了,而且報告日期推遲到了下週三,因此任務重心由“在4月12日之前準備好(推遲了)機器學習的最終報告——《暢想無監督學習》”變爲了補充機器學習所需的數學知識(線性代數與概率統計)
2.完成專業課的作業(流體機械能轉化、生物質能,新能源熱利用可以往後稍稍);
3.備戰藍橋杯,爲此:①1h左右的典型算法補充(優先Leetcode“探索”模塊);②C/C++語法知識;③常見數據結構的構造與基本操作實現;④必要的練習與練題總結(比如時長1:30虛擬競賽與“覆盤”)

2.2今日計劃表

04-07

2.3實際時間分配

  1. 今天玩嗨了,以後要注意;
  2. 至於洗漱超時,主要是今天洗了澡
圖1 時間分配
圖2 目標達成情況

3. 二叉樹的結構構造與常用操作實現

今天上午自己寫了個cpp程序把二叉樹實現了一下,爲了寫起來方便沒把結構定義放在頭文件中,途中遇到一個低級失誤:在實現完先序遍歷後,準備寫中序和後序遍歷函數時,忘記把函數體內的遞歸函數的名稱改了,導致結果與預期不符,我找錯誤用了半個小時,真的心態有點小崩。教訓就是:對於遞歸問題,Ctrl+C/V時一定要留意內部調用的函數是否需要變化

以下是實現的cpp代碼:

#include<iostream>
#include<cstdlib>
#include<queue>
using namespace std;
typedef int elem;
typedef struct TreeNode{
	elem val;
	struct TreeNode* left,*right;
}BiNode,*BiTree; 

void visit(elem val){//訪問操作
	cout<<val<<endl;
}
void PreOrderTraverse(BiTree T){//先序遍歷
	if(T){
		visit(T->val);
		PreOrderTraverse(T->left);
		PreOrderTraverse(T->right);		
	}
}

void PostOrderTraverse(BiTree T){//後序遍歷
	if(T){
		//論複製粘貼的壞處,困擾了我半小時 
		//PreOrderTraverse(T->left);
		//PreOrderTraverse(T->right);
		PostOrderTraverse(T->left);
		PostOrderTraverse(T->right);
		visit(T->val);	
	}

}

void InOrderTraverse(BiTree T){//中序遍歷
	if(T){
		//PreOrderTraverse(T->left);
		InOrderTraverse(T->left);
		visit(T->val);
		//PreOrderTraverse(T->right);	
		InOrderTraverse(T->right);
	}

}
//假定元素非負 
void CreateBiTree(BiTree *T){//樹的構建
	int x;
	cin>>x;
	if(x<0) return;
	else{
		*T=(BiNode*)malloc(sizeof(BiNode));
		(*T)->val=x;
		(*T)->left=NULL;
		(*T)->right=NULL;
		CreateBiTree(&((*T)->left));//->的優先級比*高 
		CreateBiTree(&((*T)->right));
	}
}
//靜態數組(假定元素不超過6個)
void LOT(BiTree T){//按層次遍歷
	if(T){
		int front=-1,rear=0;
		BiTree queue[6];
		BiTree p;
		queue[0]=T;
		while(front<rear){
			p=queue[++front];
			visit(p->val);
			if(p->left)
				queue[++rear]=p->left;
			if(p->right)
				queue[++rear]=p->right;
		}
	}
	
}
//STL模板 
void LayerOrderTraverse(BiTree T){//按層次遍歷
	if(T){
		queue<BiTree> q;
		BiTree p;
		q.push(T);
		while(!q.empty()){
			p=q.front();
			q.pop();
			visit(p->val);
			if(p->left)
				q.push(p->left);
			if(p->right)
				q.push(p->right);	
		}
	} 
}
int main(){
	BiTree T;
	CreateBiTree(&T); 
	cout<<"DLR"<<endl;
	PreOrderTraverse(T);
	cout<<"LRD"<<endl;
	PostOrderTraverse(T);
	cout<<"LDR"<<endl;
	InOrderTraverse(T);
	cout<<"LayerOrderTraverse:"<<endl;
	//LayerOrderTraverse(T);
	LOT(T);
	free(T);
	return 0;
} 

4. LeetCode探索:二叉樹的典型操作實現

目前Leetcode二叉樹部分完成了2/3,還剩下總結篇的六道算法題。做這些題的目的便是熟悉競賽時的風格,畢竟對於同一個知識點可能在形式上會有所變化。

4.1 實現過程中遇到的ERROR

先擺上在Leetcode上調試時遇到的幾個問題:

  1. 【ERROR】Vector declaration “expected parameter declarator”
    在stack-overflow上看到的一個解答如下:
    在這裏插入圖片描述
    意思是,對於容器變量的初始化,一定不要放在函數之外(可以聲明,但是不能定義),這個也困擾了我很久(找時間一定要好好看看容器模板)。例如以下寫法就是錯誤的:
    在這裏插入圖片描述
  2. 【ERROR】reference binding to null pointer of type ‘value_type’
    這個問題很有可能是數組(容器)越界了,要檢查下相關的數組(容器)下標是否越界。

4.2 Leetcode探索闖關題解記錄

以下是今日闖關的4道題,大多是用遞歸實現的,關於遍歷(上午的代碼已經展示過了)操作就不再列出了。部分題可以用迭代,但是暫時還不會。

Stage 01 二叉樹的層序遍歷
【題目描述】
在這裏插入圖片描述
這個應該令我印象最爲深刻的一道題了,儘管層序遍歷之前寫過了,但就因爲它的返回值形式使得這道題的寫法大變樣,要考慮層次以及容器的擴容。費了不少時間,以下是我的解法:

/**
 * 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>> v;
    vector<vector<int>> levelOrder(TreeNode* root) {
        if(root){
            queue<pair<TreeNode*,int> >q;
            TreeNode* node;
            q.push(make_pair(root,0)); //<node,level>
            int cur_size=0; //v的當前數組元素個數
            while(!q.empty()){
                pair<TreeNode*,int>p=q.front();
                
                node=p.first;
                q.pop();
                if(cur_size<=p.second){
                    cur_size=p.second+1;
                    v.resize(cur_size);
                }           
                v[p.second].push_back(p.first->val);
                
                if(node->left)
                    q.push(make_pair(node->left,p.second+1));
                if(node->right)
                    q.push(make_pair(node->right,p.second+1));
                
            } 
        }
        return v;

    }
};

Stage 02 二叉樹的最大深度
【題目描述】
在這裏插入圖片描述
有自頂向下(top-down)以及自底向上(bottom-up)兩種方法,選取方法的原則如下,我採用的是後者。
在這裏插入圖片描述

/**
 * 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:
    int ans=0;
    int max(int a,int b){
        return a>b?a:b;
    }
    int maxDepth(TreeNode* root) {
        if(!root)
            return 0;
        return max(maxDepth(root->left),maxDepth(root->right))+1;
    }
};

Stage 03 對稱二叉樹
【題目描述】
在這裏插入圖片描述
想了挺久的(主要是遞歸的方向選錯了),不過看了別人的思路後很快就實現了。

/**
 * 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:
    bool isSymmetric(TreeNode* nl,TreeNode* nr){
        if(!nl&&!nr)//兩子樹均爲空
            return true;
        if(nl&&!nr||!nl&&nr)//一個爲空,另一個不爲空
            return false;
        if(nl->val!=nr->val)//判斷兩子樹的節點是否相同
            return false;
        return isSymmetric(nl->left,nr->right)&
        isSymmetric(nl->right,nr->left);        
    }
    bool isSymmetric(TreeNode* root) {
        if(!root)//空樹被認爲是對稱的
            return true;
        return isSymmetric(root->left,root->right);
    }
};

Stage 04 路徑總和
【題目描述】
在這裏插入圖片描述
這個遞歸挺好想的,實現如下:

/**
 * 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:
    bool hasPathSum(TreeNode* root, int sum) {
        if(!root)//空樹返回false
            return false;
        if(!root->left&&!root->right)//葉子節點
            return sum==root->val;
        return hasPathSum(root->left,sum-root->val)|
        hasPathSum(root->right,sum-root->val);
    }
};

回想半年前,還在旁聽數據結構的時候,當時是多麼地抵觸”樹”,現在覺得好像也就那樣(當然現在實現的操作都是些皮毛啦),這也是爲何“早接觸一些東西總會是好的”的緣故吧!

【明日計劃】

04-08

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章