数据结构与算法题目集7-31——笛卡尔树

版权声明:我的GitHub:https://github.com/617076674。真诚求星! https://blog.csdn.net/qq_41231926/article/details/84888050

我的数据结构与算法题目集代码仓:https://github.com/617076674/Data-structure-and-algorithm-topic-set

原题链接:https://pintia.cn/problem-sets/15/problems/858

题目描述:

知识点:树的中序遍历、递归

思路一:用中序遍历是否递增来判别K1是否满足二分搜索树的性质,用后序遍历,即递归判别K2是否满足最小堆的性质

有一种很容易犯的错误,是简单地用后序遍历进行判断K1是否满足二分搜索树的性质,即递归地分别检查左右子树是否满足二分搜索树的性质:若是,则比较根节点的K1与其左右孩子K1的相对大小,若根节点K1居中,则返回真;否则返回假。

这种做法无法通过测试点4,其错误的根源在于,二分搜索树的根节点K1不仅仅要大于其左孩子的K1,而是必须大于整个左子树里所有节点的K1;对右子树同理。所以如果用递归后序遍历进行判断,我们不仅需要判断子树是否满足二分搜索树的性质,还必须通过参数传递该子树中所有节点的最大和最小K1值。需要判断根节点的K1值是否居于左子树的最大值和右子树的最小值之间。

时间复杂度是O(N)。由于采用静态数组的形式在全局变量里定义了节点,因此空间复杂度是O(1000)。

C++代码:

#include<iostream>
#include<vector>

using namespace std;

struct node{
	int K1, K2, lchild, rchild;
};

int N;
node Node[1000];
vector<int> inOrder;

void inOrderTraversal(int head);
bool judge1(int head);
bool judge2(int head);

int main(){
	std::ios::sync_with_stdio(false);
	cin >> N;
	bool flag[N];
	fill(flag, flag + N, false);
	for(int i = 0; i < N; i++){
		cin >> Node[i].K1 >> Node[i].K2 >> Node[i].lchild >> Node[i].rchild;
		if(Node[i].lchild != -1){
			flag[Node[i].lchild] = true;
		}
		if(Node[i].rchild != -1){
			flag[Node[i].rchild] = true;
		}
	}
	int head = -1;
	for(int i = 0; i < N; i++){
		if(!flag[i]){
			head = i;
			break;
		}
	}
	if(judge1(head) && judge2(head)){
		cout << "YES" << endl;
	}else{
		cout << "NO" << endl;
	}
	return 0;
}

void inOrderTraversal(int head){
	if(head == -1){
		return;
	}
	inOrderTraversal(Node[head].lchild);
	inOrder.push_back(Node[head].K1);
	inOrderTraversal(Node[head].rchild);
}

bool judge1(int head){
	inOrderTraversal(head);
	for(int i = 1; i < inOrder.size(); i++){
		if(inOrder[i] <= inOrder[i - 1]){
			return false;
		}
	}
	return true;
}

bool judge2(int head){
	if(head == -1){
		return true;
	}
	if(Node[head].lchild != -1 && Node[Node[head].lchild].K2 <= Node[head].K2){
		return false;
	}
	if(Node[head].rchild != -1 && Node[Node[head].rchild].K2 <= Node[head].K2){
		return false;
	}
	return judge2(Node[head].lchild) && judge2(Node[head].rchild);
}

C++解题报告:

思路二:用思路一中的分析,即判断根节点的K1值是否居于左子树的最大值和右子树的最小值之间,以此递归判断K1是否满足二分搜索树的性质

我们需要两个函数:

(1)int findMin(int head):用以寻找以head为根节点的树中的最小K1值。

(2)int findMax(int head):用以寻找以head为根节点的树中的最大K1值。

时间复杂度分析比较复杂。空间复杂度是O(1000)。

C++代码:

#include<iostream>

using namespace std;

struct node {
	int K1, K2, lchild, rchild;
};

int N;
node Node[1000];

int findMin(int head);
int findMax(int head);
bool judge1(int head);
bool judge2(int head);

int main() {
	std::ios::sync_with_stdio(false);
	cin >> N;
	bool flag[N];
	fill(flag, flag + N, false);
	for(int i = 0; i < N; i++) {
		cin >> Node[i].K1 >> Node[i].K2 >> Node[i].lchild >> Node[i].rchild;
		if(Node[i].lchild != -1) {
			flag[Node[i].lchild] = true;
		}
		if(Node[i].rchild != -1) {
			flag[Node[i].rchild] = true;
		}
	}
	int head = -1;
	for(int i = 0; i < N; i++) {
		if(!flag[i]) {
			head = i;
			break;
		}
	}
	if(judge1(head) && judge2(head)) {
		cout << "YES" << endl;
	} else {
		cout << "NO" << endl;
	}
	return 0;
}

int findMin(int head){
	if(Node[head].lchild == -1 && Node[head].rchild == -1){
		return Node[head].K1;
	}
	if(Node[head].lchild != -1 && Node[head].rchild != -1){
		return min(Node[head].K1, min(findMin(Node[head].lchild), findMin(Node[head].rchild)));
	}
	if(Node[head].lchild != -1 && Node[head].rchild == -1){
		return min(Node[head].K1, findMin(Node[head].lchild));
	}
	return min(Node[head].K1, findMin(Node[head].rchild));
}

int findMax(int head){
	if(Node[head].lchild == -1 && Node[head].rchild == -1){
		return Node[head].K1;
	}
	if(Node[head].lchild != -1 && Node[head].rchild != -1){
		return max(Node[head].K1, max(findMax(Node[head].lchild), findMax(Node[head].rchild)));
	}
	if(Node[head].lchild != -1 && Node[head].rchild == -1){
		return max(Node[head].K1, findMax(Node[head].lchild));
	}
	return max(Node[head].K1, findMax(Node[head].rchild));	
}

bool judge1(int head) {
	if(head == -1) {
		return true;
	}
	if(Node[head].lchild != -1 && findMax(Node[head].lchild) >= Node[head].K1) {
		return false;
	}
	if(Node[head].rchild != -1 && findMin(Node[head].rchild) <= Node[head].K1) {
		return false;
	}
	return judge1(Node[head].lchild) && judge1(Node[head].rchild);
}

bool judge2(int head) {
	if(head == -1) {
		return true;
	}
	if(Node[head].lchild != -1 && Node[Node[head].lchild].K2 <= Node[head].K2) {
		return false;
	}
	if(Node[head].rchild != -1 && Node[Node[head].rchild].K2 <= Node[head].K2) {
		return false;
	}
	return judge2(Node[head].lchild) && judge2(Node[head].rchild);
}

C++解题报告:

猜你喜欢

转载自blog.csdn.net/qq_41231926/article/details/84888050
今日推荐