蓝桥杯第十一届上半场:BST插入节点问题

蓝桥杯第十一届上半场:BST插入节点问题

前言

这是蓝桥杯第十一届2020省赛 Java b组 第九题。

题目描述

给定一棵包含 N 个节点的二叉树,节点编号是 1 ∼ N。其中 i 号节点具有权值 Wi,并且这些节点的权值恰好形成了一棵排序二叉树 (BST)。现在给定一个节点编号 K,小明想知道,在这 N 个权值以外,有多少个整数 X (即 X 不等于任何 Wi ) 满足:给编号为 K 的节点增加一个权值为 X 的子节点,仍可以得到一棵 BST。例如在下图中,括号外的数字表示编号、括号内的数字表示权值。编号1 ∼ 4 的节点权值依次是 0、10、20、30。
在这里插入图片描述

如果 K = 1,那么答案为 0。因为 1 号节点已经有左右子节点,不能再增加子节点了。
如果 K = 2,那么答案为无穷多。因为任何一个负数都可以作为 2 的左子节点。
如果 K = 3,那么答案为 9。因为 X = 11, 12, · · · , 19 都可以作为 3 的左子节点。
【输入格式】
第一行包含 2 个整数 N 和 K。
以下 N 行每行包含 2 个整数,其中第 i 行是编号为 i 的节点的父节点编号Pi 和权值 Wi 。注意 Pi = 0 表示 i 是根节点。输入保证是一棵 BST。
【输出格式】
一个整数代表答案。如果答案是无穷多,输出 −1。
【样例输入】
4 3
0 10
1 0
1 20
3 30
【样例输出】
9
【评测用例规模与约定】
对于 60% 的评测用例,1 ≤ K ≤ N ≤ 100,0 ≤ Wi ≤ 200,且 Wi 各不相同。
对于所有评测用例,1 ≤ K ≤ N ≤ 10000,0 ≤ Wi ≤ 100000000,且 Wi 各不相同。

思路

我们知道BST的特点,右永远比左大,看完题目之后,看K节点的情况对应的答案?

一、答案为-1,即K节点孩子节点权值可以无穷多时,有3种情况:

  1. K节点刚好为叶子节点(如K= 4或K= 2),那么答案就是无穷多了
  2. K节点在右子树,K节点缺一个右孩子,那么答案就是无穷多了
  3. K节点在左子树,K节点缺一个左孩子,那么答案也是无穷多,因为题目说可以取负数

二、答案为0,只有一种情况,就是K节点既有左孩子又有右孩子

三、其它答案,如案例中,K= 3时,答案其实等于 K的权值 - Father权值 - 1(题目要求权值不能重复); res = Math.abs(kWeight - fatherWight) - 1,所以就是 abs(20 - 30 )- 1 = 9;

为什么要加绝对值,大家可以画图理解~;

代码重点在于:如何判断叶子节点,是否只有左孩子,或者是否只有右孩子, 是否同时存在左右孩子?

在处理输入时我们使用parents数组存N编号(i+1)节点的父亲,如1节点是根节点,它没有父亲,所以为0,样例中parents为{ 0, 1, 1, 3 };
为什么要提这个parents数组,因为判断是否叶子节点,是否存在左、右孩子,是否都存在,这个数组至关重要;最后权值与节点我用的是map映射;

  1. 如果parents数组中不存在K,证明K节点是叶子节点,因为parents存着所有节点的父亲
  2. 存在2个K节点,证明K是两个孩子的父亲,即返回-1
  3. 1个K要判断是左孩子,还是右孩子,这个很简单,我们把K的孩子权值拿出来,如果childWeight > kWeight,那就是右孩子

依此类推;

java代码

package _2020_A;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;

public class _09BST插入节点问题 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int k = sc.nextInt();
		int[] parent = new int[n];
		HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
		for(int i = 0; i < n; i++) {
			parent[i] = sc.nextInt();
			map.put(i+1, sc.nextInt());
		}
		ArrayList<Integer> childs = new ArrayList<Integer>();
		int rootWeight = map.get(1);
		int kWeight = map.get(k); 
		for(int i = 0; i < parent.length; i++) {
			if(k == parent[i]) childs.add(map.get(i+1));
		}
		// 1.parents不存在的节点就是叶子节点,叶子节点的答案是无穷大
		if(childs.size() == 0) {
			System.out.println("叶子节点");
			System.out.println(-1);  
			return;
		} 
		// 2. 已经有左右孩子,答案是0
		else if(childs.size() == 2) {
			System.out.println("已经有左右孩子了");
			System.out.println(0);
			return;
		}
		// 3. 在右子树:k节点有左无右时为-1;在左子树:k几点有右无左为-1
		else if(childs.size() == 1 && (kWeight > rootWeight && childs.get(0) < kWeight) || (kWeight < rootWeight && childs.get(0) > kWeight)) {
			System.out.println(-1);
			return;
		}
		else {
			int fatherWeight = map.get(parent[k-1]);
			System.out.println(Math.abs(kWeight-fatherWeight)-1);
			return;
		}
	}

}

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值