A+B with Binary Search Tree(pta)

数据结构的题目,题目给出了输入输出,所以只用核心算法,两种,第一种会有一个测试点超时,因为时间复杂度接近N^2,想看正确答案可以直接移步第二种答案。第二种时间复杂度接近2N.对于2*10^4的数据体量来说降了很多。

第一种思路:对于root1左根右非递归遍历(由于二叉搜索树的特征,这样得到的就是升序),同时对于root1的每一个结点数据,先遍历一遍a看a中是否已经有这个节点,再调用Find函数去找root2里是否有这个节点。入锅满足连个要求就把T->val存储。

缺点:时间复杂度接机N^2,对于重复结点的判断没有必要专门遍历一遍a,完全可以直接和a[i-1]去比,因为按照升序序列遍历,相同的两个节点本身就连在一起。Find函数也是每一次都从root2的根开始遍历,没有必要。这些都在第二种方法里改进了。

int Find(TreeNode* T,int c){
	if(T){
		if(c==T->val) return 1;
		if(c>T->val){
			return Find(T->right,c);
		}
		else return Find(T->left,c);
	}
	return 0;
} 
//左根右升序 ,中序遍历root1
int findSum(TreeNode *root1, TreeNode *root2, int target, int a[], int b[]){
	TreeNode* stack[99999];
	int top=-1,t,i=0,j=0,f;
	TreeNode *T=root1;
	while(T||top!=-1){
		while(T){
			stack[++top]=T;
			T=T->left;
		}
		T=stack[top--];
		f=1;
		for(j=0;j<i;j++){
			if(a[j]==T->val){
				f=0;
				break;
			}
		}
		if(f&&Find(root2,target-T->val)){
			a[i]=T->val;
			b[i++]=target-T->val;
		}
		T=T->right;
	}
	return i;
}

第二种方法(正确的)思路:先对root2左根右遍历得到升序序列并存在数组B里,遍历完后B的下标ib正好在最后一个元素的位置,再对root1左根右升序遍历,同时对每一个结点的值T->val,先和a[ia]比较是否相等,再和B[ib]比较,如果二者的和大于target就ib--,B向前走,直到等于或者小于时即可跳出,若等于还要存储在a里。当ib<0或者while不满足是说明其中一棵树遍历完了则结束。

注意数组元素最大限,这个段错误卡了我很久没找出来,还以为算法有问题。

int findSum(TreeNode *root1, TreeNode *root2, int target, int a[], int b[]){
	TreeNode* stack[99999];//最多5个9再多就段错误了 
	int top=-1,ib=-1,ia=0,f2,B[99999];
	TreeNode *T=root2;
	while(T||top!=-1){
		while(T){
			stack[++top]=T;
			T=T->left;//注意root2是也是左根右读 
		}
		T=stack[top--];
		B[++ib]=T->val;
		T=T->right;
	} 
	T=root1;//再遍历A但不存储 
	while(T||top!=-1){
		while(T){
			stack[++top]=T;
			T=T->left;
		}
		T=stack[top--];
		if((ia==0)||((ia>0)&&(a[ia-1]!=T->val))){//不和前一个元素重复 
			f2=0;
			while(ib>=0){
				if(B[ib]+T->val>=target){
					if(B[ib]+T->val==target){
						f2=1; 
						break;
					}
					else ib--; //B向前走 
				}
				else break;
			}
		    if(f2){
				a[ia]=T->val;
				b[ia++]=target-T->val;
			}
			if(ib<0) break;//root2的元素已经走完了 
		}
		T=T->right;
	}
	return ia;
}

题目如下:

A Binary Search Tree (BST) is recursively defined as a binary tree which has the following properties:

  • The left subtree of a node contains only nodes with keys less than the node's key.

  • The right subtree of a node contains only nodes with keys greater than or equal to the node's key.

  • Both the left and right subtrees must also be binary search trees.

Given two binary search trees, T1 and T2, and an integer N, you are supposed to find a number A from T1 and a number B from T2 such that A+B=N.

Structure description:

The tree structure is shown below:

 

typedef struct TreeNode { int val; struct TreeNode *left, *right; } TreeNode;

Function definition:

You should find all solutions satisfying A+B=N. The function definition is as follows:

 

int findSum(TreeNode *root1, TreeNode *root2, int target, int a[], int b[]);

root1 and root2 are the roots for T1 and T2 respectively. The number of nodes for each tree n ≤2×104,

and key value of each node k: −2×109≤k≤2×109. N is the target number. For each test case, the function returns nsum, the number of solutions, then saves all the solutions in a and b. That is, each solution is in the format N = a[i] + b[i](0≤i<nsum). In case there are multiple solutions, values in a must be in ascending order. Note: the same solution should be saved only once.

Input Specification:

Each input file contains one test case. Each case gives the information of T1, T2, and N, in the following format:
The first line contains a positive integer n1​ (≤2×104), which is the number of nodes in T1. Then n1​ lines follow, where the i-th line contains the key value k (−2×109≤k≤2×109) and the parent node index of the i-th node (0≤i<n1​). Since the root has no parent, its parent index is defined to be −1. After T1, T2 is given in the same format as T1. Finally, the last line gives the target N (with the same range of k).

Output Specification:

Firstly, you should print in a line true if at least one solution exists, then output all the solutions in the following lines, each in the format N = A + B. In the case of multiple solutions, you must ensure that values A are in ascending order. Note: the same equation should be printed only once. If there is no solution, simply print false.

Test program example:

#include <stdio.h>
#include <stdlib.h>

#define MAX_SIZE 20000

int values_1[MAX_SIZE];
int parents_1[MAX_SIZE];

int values_2[MAX_SIZE];
int parents_2[MAX_SIZE];

typedef struct TreeNode {
    int val;
    struct TreeNode *left, *right;
} TreeNode;

TreeNode *buildTree(int values[], int parents[], int n); /* details omitted */

int findSum(TreeNode *root1, TreeNode *root2, int N, int a[], int b[]);

int main() {

    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++) {
        scanf("%d %d", &values_1[i], &parents_1[i]);
    }

    int m;
    scanf("%d", &m);
    for (int i = 0; i < m; i++) {
        scanf("%d %d", &values_2[i], &parents_2[i]);
    }

    int N;
    scanf("%d", &N);

    TreeNode *root1 = buildTree(values_1, parents_1, n);
    TreeNode *root2 = buildTree(values_2, parents_2, m);

    int a[MAX_SIZE];
    int b[MAX_SIZE];
    int nsum = findSum(root1, root2, N, a, b);

    if (nsum) {
        printf("true\n");
        for (int i = 0; i < nsum; i++)
            printf("%d = %d + %d\n", N, a[i], b[i]);
    } else
        printf("false\n");

    return 0;
}

int findSum(TreeNode *root1, TreeNode *root2, int N, int a[], int b[]) {
    /* your implementation of this function */
}

Sample Input 1:

8
12 2
16 5
13 4
18 5
15 -1
17 4
14 2
18 3
7
20 -1
16 0
25 0
13 1
18 1
21 2
28 2
36

Sample Output 1:

true
36 = 15 + 21
36 = 16 + 20
36 = 18 + 18


Sample Input 2:

5
10 -1
5 0
15 0
2 1
7 1
3
15 -1
10 0
20 0
40

Sample Output 2:

false
### 如何使用二叉搜索树(BST)实现 A+B 操作 在 C 编程语言中,可以通过构建两个二叉搜索树(BST),分别表示集合 A 和 B 的元素,然后通过遍历其中一个 BST 并将其节点插入到另一个 BST 中来完成 A+B 操作。以下是详细的实现方法: #### 数据结构定义 首先需要定义一个简单的二叉搜索树节点的数据结构。 ```c typedef struct TreeNode { int value; struct TreeNode* left; struct TreeNode* right; } TreeNode; ``` #### 插入函数 为了向 BST 添加新元素,可以编写如下 `insert` 函数。 ```c TreeNode* createNode(int value) { TreeNode* newNode = (TreeNode*)malloc(sizeof(TreeNode)); newNode->value = value; newNode->left = NULL; newNode->right = NULL; return newNode; } void insert(TreeNode** root, int value) { if (*root == NULL) { *root = createNode(value); } else { if (value < (*root)->value) { insert(&((*root)->left), value); // Insert into the left subtree. } else if (value > (*root)->value) { insert(&((*root)->right), value); // Insert into the right subtree. } // If value == (*root)->value, do nothing since duplicates are not allowed in a set. } } ``` #### 合并操作 要执行 A+B 操作,即合并两棵 BST,可以从一棵树中提取所有元素并将它们逐个插入另一棵树中。 ```c // In-order traversal to extract elements from one tree and add them to another. void mergeTrees(TreeNode* sourceRoot, TreeNode** targetRoot) { if (sourceRoot != NULL) { mergeTrees(sourceRoot->left, targetRoot); // Traverse left subtree first. insert(targetRoot, sourceRoot->value); // Add current node's value to target tree. mergeTrees(sourceRoot->right, targetRoot); // Then traverse right subtree. } } ``` #### 主程序逻辑 假设我们已经初始化了两棵 BST 表示集合 A 和 B,则可以通过调用上述函数完成 A+B 操作。 ```c int main() { TreeNode* treeA = NULL; TreeNode* treeB = NULL; // Example: Adding values to Tree A. int arrayA[] = {5, 3, 7, 2, 4}; for (size_t i = 0; i < sizeof(arrayA)/sizeof(arrayA[0]); ++i) { insert(&treeA, arrayA[i]); } // Example: Adding values to Tree B. int arrayB[] = {6, 8, 1}; for (size_t i = 0; i < sizeof(arrayB)/sizeof(arrayB[0]); ++i) { insert(&treeB, arrayB[i]); } // Perform A + B by merging all nodes of treeB into treeA. mergeTrees(treeB, &treeA); // Now treeA contains all unique elements from both sets. return 0; } ``` 此代码片段展示了如何利用二叉搜索树的性质高效地进行集合并集运算[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值