前言
LeetCode第95题是一个很妙的存在,今天分享一下比较详细的解题思路和方法。
提示:若有错误,请联系我进行改正,望各位大佬不吝赐教
一、题目描述
根据LeetCode官方的题目概述可以知道,本题的大致意思为:给你一个整数 n ,请你生成并返回所有由 n 个节点组成且节点值从 1 到 n 互不相同的不同 二叉搜索树 。可以按 任意顺序 返回答案。
二、问题剖析和解题思路分析
1.二叉搜索树
简单的说,二叉搜索树的意思就是根结点的左子树的所有结点的值都比它小,所有右子树的结点的值都比它大,这样的二叉树叫二叉搜索树。
2.问题剖析
题目的意思就是给定我们一个随机数 n ,让我们找出结点值从 1 ~ n 的所有二叉搜索树,并将它们全部返回。
First:
我们能从题目中知道,根节点是从 1 ~n 的,也就是说,在[1 ,n]的范围内每个点都有可能是根节点。
Second:
在每个根节点下都会有左右两个子树,而左右两个子树的根节点的儿子节点又可以看作是左右两个子树的根节点。假设当前根节点是 a 点,那么左右子树的根节点的取值分别是:左子树的根节点:1 ~ (a-1);右子树的根节点是:(a+1)~n。
Third:
同样,按照Second中的思路一直延续下去,直到所有的点都被遍历到。也就是不断递归的过程。
3.代码展示
Python代码:
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def generateTrees(self, n: int) -> List[TreeNode]:
def generateTrees(start, end):
if start > end:
return [None]
allTrees = []
for i in range(start, end + 1): # 枚举可行根节点
# 获得所有可行的左子树集合
leftTrees = generateTrees(start, i - 1)
# 获得所有可行的右子树集合
rightTrees = generateTrees(i + 1, end)
# 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for l in leftTrees:
for r in rightTrees:
currTree = TreeNode(i)
currTree.left = l
currTree.right = r
allTrees.append(currTree)
return allTrees
return generateTrees(1, n) if n else []
C++代码:
class Solution {
public:
vector<TreeNode*> generateTrees(int start, int end) {
if (start > end) {
return { nullptr };
}
vector<TreeNode*> allTrees;
// 枚举可行根节点
for (int i = start; i <= end; i++) {
// 获得所有可行的左子树集合
vector<TreeNode*> leftTrees = generateTrees(start, i - 1);
// 获得所有可行的右子树集合
vector<TreeNode*> rightTrees = generateTrees(i + 1, end);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (auto& left : leftTrees) {
for (auto& right : rightTrees) {
TreeNode* currTree = new TreeNode(i);
currTree->left = left;
currTree->right = right;
allTrees.emplace_back(currTree);
}
}
}
return allTrees;
}
vector<TreeNode*> generateTrees(int n) {
if (!n) {
return {};
}
return generateTrees(1, n);
}
};
C语言代码
struct TreeNode** buildTree(int start, int end, int* returnSize) {
if (start > end) {
(*returnSize) = 1;
struct TreeNode** ret = malloc(sizeof(struct TreeNode*));
ret[0] = NULL;
return ret;
}
*returnSize = 0;
struct TreeNode** allTrees = malloc(0);
// 枚举可行根节点
for (int i = start; i <= end; i++) {
// 获得所有可行的左子树集合
int leftTreesSize;
struct TreeNode** leftTrees = buildTree(start, i - 1, &leftTreesSize);
// 获得所有可行的右子树集合
int rightTreesSize;
struct TreeNode** rightTrees = buildTree(i + 1, end, &rightTreesSize);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (int left = 0; left < leftTreesSize; left++) {
for (int right = 0; right < rightTreesSize; right++) {
struct TreeNode* currTree = malloc(sizeof(struct TreeNode));
currTree->val = i;
currTree->left = leftTrees[left];
currTree->right = rightTrees[right];
(*returnSize)++;
allTrees = realloc(allTrees, sizeof(struct TreeNode*) * (*returnSize));
allTrees[(*returnSize) - 1] = currTree;
}
}
free(rightTrees);
free(leftTrees);
}
return allTrees;
}
struct TreeNode** generateTrees(int n, int* returnSize) {
if (!n) {
(*returnSize) = 0;
return NULL;
}
return buildTree(1, n, returnSize);
}
本代码转自:C语言代码
Java代码:
class Solution {
public List<TreeNode> generateTrees(int n) {
if (n == 0) {
return new LinkedList<TreeNode>();
}
return generateTrees(1, n);
}
public List<TreeNode> generateTrees(int start, int end) {
List<TreeNode> allTrees = new LinkedList<TreeNode>();
if (start > end) {
allTrees.add(null);
return allTrees;
}
// 枚举可行根节点
for (int i = start; i <= end; i++) {
// 获得所有可行的左子树集合
List<TreeNode> leftTrees = generateTrees(start, i - 1);
// 获得所有可行的右子树集合
List<TreeNode> rightTrees = generateTrees(i + 1, end);
// 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for (TreeNode left : leftTrees) {
for (TreeNode right : rightTrees) {
TreeNode currTree = new TreeNode(i);
currTree.left = left;
currTree.right = right;
allTrees.add(currTree);
}
}
}
return allTrees;
}
}
本代码转自:Java代码
总结
作为算法小白,我只能一步步的去提升,希望星光不负有心人。念念不忘,必有回响。
大家在阅读时若发现有误,请联系我进行更改,鄙人将非常感谢大家给我的学习机会和面对自己错误的机会。