1. 程式人生 > >PAT-ADVANCED1004——Counting Leaves

PAT-ADVANCED1004——Counting Leaves

我的PAT-ADVANCED程式碼倉:https://github.com/617076674/PAT-ADVANCED

原題連結:https://pintia.cn/problem-sets/994805342720868352/problems/994805521431773184

題目描述:

題目翻譯:

1004 數葉子

家庭層級通常由譜系樹呈現。 你的工作是統計那些沒有孩子的家庭成員。

輸入格式:

每個輸入檔案包含一個測試用例。在每個測試用例中,第一行給出了兩個數字:0 < N < 100,代表樹中的節點個數;M( < N)代表非葉子節點個數。接下來的M行,每行都是下述格式:

ID K ID[1] ID[2] ... ID[K]

ID是一個2位數字,表示一個非葉子節點,K是該節點的孩子數量,緊跟著的是一串ID值以及該ID值對應的孩子數量。為了簡便,我們假設根節點的ID值是01。

輸出格式:

對每個測試用例,從根結點開始,每一層你都需要統計那些沒有孩子的成員。數字必須在1行內輸出,每個數字間隔一個空格,行末不得有多餘空格。

這個簡單的例子只有2個節點,01代表根節點,02是它的唯一孩子。因此在和01同一層的節點中,沒有葉子節點。而在下一層,有一個葉子節點。因此我們需要在1行內輸出0 1。

輸入樣例:

2 1
01 1 02

輸出樣例:

0 1

知識點:樹的層序遍歷、樹的深度優先遍歷

思路一:樹的層序遍歷

本題的關鍵在於一棵普通樹的儲存。我們採取和PAT-ADVANCED1053——Path of Equal Weight同樣的思路,用靜態寫法,事先開一個大小不低於節點上限個數的節點陣列,用vector<int>型的變數來儲存陣列中的索引來代替指標域。

本解決思路和LeetCode102——二叉樹的層序遍歷思路一模一樣,只不過LeetCode102——二叉樹的層序遍歷中的是一顆二叉樹,而本題中的數並不一定是一顆二叉樹。

在滿足佇列不為空條件的這個外迴圈裡,我們先記錄每一層的節點個數,即此時佇列中存放的節點個數,記作qSize。每出隊操作qSize個節點後的統計得到的葉子節點數是同一層的葉子節點數

,這樣就實現了分層計數的目的。將每層的計數結果儲存在一個vector<int>型的變數leaves中即可。

時間複雜度和空間複雜度都是O(N)。

C++程式碼:

#include<iostream>
#include<vector>
#include<queue> 

using namespace std;

struct node {
	int num;
	vector<int> child;
};

int N;	//節點總數
int M;	//非葉子節點數
node Node[100];
vector<int> leaves;	//存放每一層的葉子節點數 

void levelTraversal(int root); 

int main(){
	cin >> N >> M;
	int ID, K, childID;
	for(int i = 0; i < M; i++){
		cin >> ID >> K;
		for(int j = 0; j < K; j++){
			cin >> childID;
			Node[ID].child.push_back(childID);
		}
	}
	levelTraversal(1);
	for(int i = 0; i < leaves.size(); i++){
		cout << leaves[i];
		if(i != leaves.size() - 1){
			cout << " ";
		}
	}
	cout << endl;
	return 0; 
}

void levelTraversal(int root){
	queue<int> q;
	q.push(root);
	while(!q.empty()){
		int qSize = q.size();
		int levelLeaves = 0;
		for(int i = 0; i < qSize; i++){
			int now = q.front();
			q.pop();
			if(Node[now].child.size() == 0){
				levelLeaves++;
			}
			for(int j = 0; j < Node[now].child.size(); j++){
				q.push(Node[now].child[j]);
			}
		}
		leaves.push_back(levelLeaves);
	} 
} 

C++解題報告:

思路二:樹的深度優先遍歷

另一個思路是使用樹的深度優先遍歷,在深度優先遍歷的時候記錄其層數,並按層數對每層進行葉子節點的計數操作。當然,輸出的時候我們必須要知道這棵樹的深度是多少,以免漏輸出或者多輸出0值。

時間複雜度和空間複雜度均是O(N)。

C++程式碼:

#include<iostream>
#include<vector>
#include<queue> 

using namespace std;

struct node {
	int num;
	vector<int> child;
};

int N;	//節點總數
int M;	//非葉子節點數
node Node[100];
int leaves[100] = {0};//存放每一層的葉子節點數
int depth; 

void dfs(int root, int level); 

int main(){
	cin >> N >> M;
	int ID, K, childID;
	for(int i = 0; i < M; i++){
		cin >> ID >> K;
		for(int j = 0; j < K; j++){
			cin >> childID;
			Node[ID].child.push_back(childID);
		}
	}
	dfs(1, 0);
	for(int i = 0; i <= depth; i++){
		cout << leaves[i];
		if(i != depth){
			cout << " ";
		}
	}
	cout << endl;
	return 0; 
}

void dfs(int root, int level){
	if(Node[root].child.size() == 0){
		leaves[level]++;
		depth = max(depth, level);
		return;
	}
	for(int i = 0; i < Node[root].child.size(); i++){
		dfs(Node[root].child[i], level + 1);
	}
}

C++解題報告: