题目描述
二叉树也可以用数组来存储,给定一个数组,树的根节点的值存储在下标1,对于存储在下标N的节点,它的左子节点和右子节点分别存储在下标2N和2N+1,并且我们用值-1代表一个节点为空。
给定一个数组存储的二叉树,试求从根节点到最小的叶子节点的路径,路径由节点的值组成。
输入描述
输入一行为数组的内容,数组的每个元素都是正整数,元素间用空格分隔。
注意第一个元素即为根节点的值,即数组的第N个元素对应下标N,下标0在树的表示中没有使用,所以我们省略了。
输入的树最多为7层。
输出描述
输出从根节点到最小叶子节点的路径上,各个节点的值,由空格分隔,用例保证最小叶子节点只有一个。
用例1
输入
3 5 7 -1 -1 2 4
输出
3 7 2
说明
最小叶子节点的路径为3 7 2。
示例2
输入
5 9 8 -1 -1 7 -1 -1 -1 -1 -1 6
输出
5 8 7 6
说明
最小叶子节点的路径为5 8 7 6,注意数组仅存储至最后一个非空节点,故不包含节点“7”右子节点的-1。
题解
思路:
- for循环寻找到最小叶子节点值位置。
- 迭代收集叶子节点到根节点经过路径的值。
c++
#include <cstdint>
#include<iostream>
#include<vector>
#include<string>
#include <utility>
#include <sstream>
#include<algorithm>
#include <cmath>
#include <climits>
using namespace std;
// 计算完全二叉树的层数
int compute_height(int N) {
return ceil(log2(N + 1));
}
bool judege(vector<int> ans, int pos) {
int n = ans.size();
return (pos >= n || ans[pos] == -1);
}
int main() {
vector<int> ans;
int tmp;
while (cin >> tmp) {
ans.push_back(tmp);
}
vector<int> res;
int n = ans.size();
// 最小叶子节点值位置
int pos = -1;
// 最小叶子节点值位置
int minValue = INT_MAX;
for (int i = 0; i < n; i++) {
int leftIndex = 2 * (i+1) -1;
int rightIndex = 2 * (i+1);
if (ans[i] == -1) {
continue;
}
// 判断是否是叶子节点
if (judege(ans, leftIndex) &&judege(ans, rightIndex)) {
if (ans[i] < minValue) {
pos = i;
minValue = ans[i];
}
}
}
// 添加叶子节点到根节点的值
while (pos != 0) {
res.push_back(ans[pos]);
pos = (pos-1) / 2;
}
res.push_back(ans[0]);
for (int i = res.size()-1; i >= 0; i--) {
cout << res[i];
if (i != 0) {
cout << " ";
}
}
return 0;
}
JAVA
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.StringJoiner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
Integer[] arr =
Arrays.stream(sc.nextLine().split(" ")).map(Integer::parseInt).toArray(Integer[]::new);
System.out.println(getResult(arr));
}
public static String getResult(Integer[] arr) {
int n = arr.length - 1;
// 最小叶子节点的值
int min = Integer.MAX_VALUE;
// 最小叶子节点的索引
int minIdx = -1;
// 求解最小叶子节点的值和索引
for (int i = n; i >= 0; i--) {
if (arr[i] != -1) {
if (i * 2 + 1 <= n && arr[i * 2 + 1] != -1) continue;
if (i * 2 + 2 <= n && arr[i * 2 + 2] != -1) continue;
if (min > arr[i]) {
min = arr[i];
minIdx = i;
}
}
}
// path用于缓存最小叶子节点到根的路径
LinkedList<Integer> path = new LinkedList<>();
path.addFirst(min);
// 从最小叶子节点开始向上找父节点,直到树顶
while (minIdx != 0) {
int f = (minIdx - 1) / 2;
path.addFirst(arr[f]);
minIdx = f;
}
StringJoiner sj = new StringJoiner(" ");
for (Integer val : path) sj.add(val + "");
return sj.toString();
}
}
Python
import sys
# 输入获取
arr = list(map(int, input().split()))
# 算法入口
def getResult(arr):
# 最小叶子节点的值
minV = sys.maxsize
# 最小节点在数组中的索引位置
minIdx = -1
n = len(arr) - 1
for i in range(n, -1, -1):
if arr[i] != -1:
if i * 2 + 1 <= n and arr[i * 2 + 1] != -1:
continue
if i * 2 + 2 <= n and arr[i * 2 + 2] != -1:
continue
if minV > arr[i]:
minV = arr[i]
minIdx = i
# path用于缓存最小叶子节点到根的路径
path = []
path.insert(0, str(minV))
# 从最小值节点开始向上找父节点,直到树顶
while minIdx != 0:
f = (minIdx - 1) // 2
path.insert(0, str(arr[f]))
minIdx = f
return " ".join(path)
# 算法调用
print(getResult(arr))
JavaScript
/* JavaScript Node ACM模式 控制台输入获取 */
const readline = require("readline");
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl.on("line", (line) => {
const arr = line.split(" ").map(Number);
let n = arr.length - 1;
// 最小叶子节点的值
let min = Infinity;
// 最小节点在数组中的索引位置
let minIdx = -1;
for (let i = n; i >= 0; i--) {
if (arr[i] != -1) {
if (i * 2 + 1 <= n && arr[i * 2 + 1] != -1) continue;
if (i * 2 + 2 <= n && arr[i * 2 + 2] != -1) continue;
if (min > arr[i]) {
min = arr[i];
minIdx = i;
}
}
}
// path用于缓存最小叶子节点到根的路径
const path = [];
path.unshift(min);
// 从最小值节点开始向上找父节点,直到树顶
while (minIdx !== 0) {
let f = Math.floor((minIdx - 1) / 2);
path.unshift(arr[f]);
minIdx = f;
}
console.log(path.join(" "));
});
Go
package main
import (
"bufio"
"fmt"
"math"
"os"
"strconv"
"strings"
)
// 判断是否叶子节点
func judge(ans []int, pos int) bool {
return pos >= len(ans) || ans[pos] == -1
}
func main() {
scanner := bufio.NewScanner(os.Stdin)
scanner.Scan()
input := scanner.Text()
inputs := strings.Fields(input)
// 将输入的字符串转换为整数数组
var ans []int
for _, val := range inputs {
num, err := strconv.Atoi(val)
if err != nil {
fmt.Println("输入无效")
return
}
ans = append(ans, num)
}
var res []int
pos := -1 // 最小叶子节点的位置
minValue := math.MaxInt // 初始化最小值为最大整数
// 找到最小叶子节点的位置
for i := 0; i < len(ans); i++ {
leftIndex := 2*(i+1) - 1 // 左子节点索引
rightIndex := 2*(i+1) // 右子节点索引
if ans[i] == -1 {
continue
}
// 判断当前节点是否为叶子节点
if judge(ans, leftIndex) && judge(ans, rightIndex) {
if ans[i] < minValue {
pos = i
minValue = ans[i]
}
}
}
// 从叶子节点回溯到根节点,收集路径上的值
for pos != 0 {
res = append(res, ans[pos])
pos = (pos - 1) / 2
}
res = append(res, ans[0]) // 添加根节点的值
// 按从根节点到叶子节点的顺序输出路径
for i := len(res) - 1; i >= 0; i-- {
fmt.Print(res[i])
if i != 0 {
fmt.Print(" ")
}
}
}