Golang每日一练(leetDay0084) BST第K小的元素、最近公共祖先

文章提供了三种方法解决二叉搜索树中找到第K小元素的问题,以及两种方法找到最近公共祖先。这些方法包括利用中序遍历的性质、迭代和递归策略。

目录

230. 二叉搜索树中第K小的元素 Kth-smallest Element In A BST  🌟🌟

235. 二叉搜索树的最近公共祖先 Lowest Common Ancestor of a BST  🌟🌟

🌟 每日一练刷题专栏 🌟

Rust每日一练 专栏

Golang每日一练 专栏

Python每日一练 专栏

C/C++每日一练 专栏

Java每日一练 专栏


230. 二叉搜索树中第K小的元素 Kth-smallest Element In A BST

给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从 1 开始计数)。

示例 1:

输入:root = [3,1,4,null,2], k = 1
输出:1

示例 2:

输入:root = [5,3,6,2,4,null,null,1], k = 3
输出:3

提示:

  • 树中的节点数为 n 。
  • 1 <= k <= n <= 10^4
  • 0 <= Node.val <= 10^4

进阶:如果二叉搜索树经常被修改(插入/删除操作)并且你需要频繁地查找第 k 小的值,你将如何优化算法?

代码1:BST特性:中序遍历会得到一个递增的序列,序列第k-1个元素即结果

package main

import (
	"fmt"
	"strings"
)

const null = -1 << 31

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func buildTree(nums []int) *TreeNode {
	if len(nums) == 0 {
		return nil
	}
	root := &TreeNode{Val: nums[0]}
	Queue := []*TreeNode{root}
	idx := 1
	for idx < len(nums) {
		node := Queue[0]
		Queue = Queue[1:]
		if nums[idx] != null {
			node.Left = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Left)
		}
		idx++
		if idx < len(nums) && nums[idx] != null {
			node.Right = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Right)
		}
		idx++
	}
	return root
}

func levelOrder(root *TreeNode) [][]int {
	res := [][]int{}
	if root == nil {
		return res
	}
	Queue := []*TreeNode{root}
	for len(Queue) > 0 {
		level := []int{}
		n := len(Queue)
		for i := 0; i < n; i++ {
			cur := Queue[0]
			Queue = Queue[1:]
			level = append(level, cur.Val)
			if cur.Left != nil {
				Queue = append(Queue, cur.Left)
			}
			if cur.Right != nil {
				Queue = append(Queue, cur.Right)
			}
		}
		res = append(res, level)
	}
	return res
}

func Array2DToString(array [][]int) string {
	if len(array) == 0 {
		return "[]"
	}
	arr2str := func(arr []int) string {
		res := "["
		for i := 0; i < len(arr); i++ {
			res += fmt.Sprint(arr[i])
			if i != len(arr)-1 {
				res += ","
			}
		}
		return res + "]"
	}
	res := make([]string, len(array))
	for i, arr := range array {
		res[i] = arr2str(arr)
	}
	return strings.Join(strings.Fields(fmt.Sprint(res)), ",")
}

func kthSmallest(root *TreeNode, k int) int {
	var res []int
	var inorder func(node *TreeNode)
	inorder = func(node *TreeNode) {
		if node == nil {
			return
		}
		inorder(node.Left)
		res = append(res, node.Val)
		inorder(node.Right)
	}
	inorder(root)
	return res[k-1]
}

func main() {
	nums := []int{3, 1, 4, null, 2}
	root := buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 1))

	nums = []int{5, 3, 6, 2, 4, null, null, 1}
	root = buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 3))
}

 代码2:中序遍历增加一个计数器 count 统计遍历到的节点个数,如果 count 等于 k,就返回当前节点值。

package main

import (
	"fmt"
	"strings"
)

const null = -1 << 31

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func buildTree(nums []int) *TreeNode {
	if len(nums) == 0 {
		return nil
	}
	root := &TreeNode{Val: nums[0]}
	Queue := []*TreeNode{root}
	idx := 1
	for idx < len(nums) {
		node := Queue[0]
		Queue = Queue[1:]
		if nums[idx] != null {
			node.Left = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Left)
		}
		idx++
		if idx < len(nums) && nums[idx] != null {
			node.Right = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Right)
		}
		idx++
	}
	return root
}

func levelOrder(root *TreeNode) [][]int {
	res := [][]int{}
	if root == nil {
		return res
	}
	Queue := []*TreeNode{root}
	for len(Queue) > 0 {
		level := []int{}
		n := len(Queue)
		for i := 0; i < n; i++ {
			cur := Queue[0]
			Queue = Queue[1:]
			level = append(level, cur.Val)
			if cur.Left != nil {
				Queue = append(Queue, cur.Left)
			}
			if cur.Right != nil {
				Queue = append(Queue, cur.Right)
			}
		}
		res = append(res, level)
	}
	return res
}

func Array2DToString(array [][]int) string {
	if len(array) == 0 {
		return "[]"
	}
	arr2str := func(arr []int) string {
		res := "["
		for i := 0; i < len(arr); i++ {
			res += fmt.Sprint(arr[i])
			if i != len(arr)-1 {
				res += ","
			}
		}
		return res + "]"
	}
	res := make([]string, len(array))
	for i, arr := range array {
		res[i] = arr2str(arr)
	}
	return strings.Join(strings.Fields(fmt.Sprint(res)), ",")
}

func kthSmallest(root *TreeNode, k int) int {
	stack := []*TreeNode{}
	count := 0
	node := root
	for node != nil || len(stack) > 0 {
		for node != nil {
			stack = append(stack, node)
			node = node.Left
		}
		node = stack[len(stack)-1]
		stack = stack[:len(stack)-1]
		count++
		if count == k {
			return node.Val
		}
		node = node.Right
	}
	return 0
}

func main() {
	nums := []int{3, 1, 4, null, 2}
	root := buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 1))

	nums = []int{5, 3, 6, 2, 4, null, null, 1}
	root = buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 3))
}

代码3:用stack迭代

package main

import (
	"fmt"
	"strings"
)

const null = -1 << 31

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func buildTree(nums []int) *TreeNode {
	if len(nums) == 0 {
		return nil
	}
	root := &TreeNode{Val: nums[0]}
	Queue := []*TreeNode{root}
	idx := 1
	for idx < len(nums) {
		node := Queue[0]
		Queue = Queue[1:]
		if nums[idx] != null {
			node.Left = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Left)
		}
		idx++
		if idx < len(nums) && nums[idx] != null {
			node.Right = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Right)
		}
		idx++
	}
	return root
}

func levelOrder(root *TreeNode) [][]int {
	res := [][]int{}
	if root == nil {
		return res
	}
	Queue := []*TreeNode{root}
	for len(Queue) > 0 {
		level := []int{}
		n := len(Queue)
		for i := 0; i < n; i++ {
			cur := Queue[0]
			Queue = Queue[1:]
			level = append(level, cur.Val)
			if cur.Left != nil {
				Queue = append(Queue, cur.Left)
			}
			if cur.Right != nil {
				Queue = append(Queue, cur.Right)
			}
		}
		res = append(res, level)
	}
	return res
}

func Array2DToString(array [][]int) string {
	if len(array) == 0 {
		return "[]"
	}
	arr2str := func(arr []int) string {
		res := "["
		for i := 0; i < len(arr); i++ {
			res += fmt.Sprint(arr[i])
			if i != len(arr)-1 {
				res += ","
			}
		}
		return res + "]"
	}
	res := make([]string, len(array))
	for i, arr := range array {
		res[i] = arr2str(arr)
	}
	return strings.Join(strings.Fields(fmt.Sprint(res)), ",")
}

func kthSmallest(root *TreeNode, k int) int {
    stack := []*TreeNode{}
    count := 0
    node := root
    for node != nil || len(stack) > 0 {
        for node != nil {
            stack = append(stack, node)
            node = node.Left
        }
        node = stack[len(stack)-1]
        stack = stack[:len(stack)-1]
        count++
        if count == k {
            return node.Val
        }
        node = node.Right
    }
    return 0
}

func main() {
	nums := []int{3, 1, 4, null, 2}
	root := buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 1))

	nums = []int{5, 3, 6, 2, 4, null, null, 1}
	root = buildTree(nums)
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(kthSmallest(root, 3))
}

输出:

[[3],[1,4],[2]]

1

[[5],[3,6],[2,4],[1]]

3


235. 二叉搜索树的最近公共祖先 Lowest Common Ancestor of a BST

给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。

最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。”

例如,给定如下二叉搜索树:  root = [6,2,8,0,4,7,9,null,null,3,5]

示例 1:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
输出: 6 
解释: 节点 2 和节点 8 的最近公共祖先是 6。

示例 2:

输入: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
输出: 2
解释: 节点 2 和节点 4 的最近公共祖先是 2, 因为根据定义最近公共祖先节点可以为节点本身。

说明:

  • 所有节点的值都是唯一的。
  • p、q 为不同节点且均存在于给定的二叉搜索树中。

代码1: 迭代

package main

import (
	"fmt"
	"strings"
)

const null = -1 << 31

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func buildTree(nums []int) *TreeNode {
	if len(nums) == 0 {
		return nil
	}
	root := &TreeNode{Val: nums[0]}
	Queue := []*TreeNode{root}
	idx := 1
	for idx < len(nums) {
		node := Queue[0]
		Queue = Queue[1:]
		if nums[idx] != null {
			node.Left = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Left)
		}
		idx++
		if idx < len(nums) && nums[idx] != null {
			node.Right = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Right)
		}
		idx++
	}
	return root
}

func levelOrder(root *TreeNode) [][]int {
	res := [][]int{}
	if root == nil {
		return res
	}
	Queue := []*TreeNode{root}
	for len(Queue) > 0 {
		level := []int{}
		n := len(Queue)
		for i := 0; i < n; i++ {
			cur := Queue[0]
			Queue = Queue[1:]
			level = append(level, cur.Val)
			if cur.Left != nil {
				Queue = append(Queue, cur.Left)
			}
			if cur.Right != nil {
				Queue = append(Queue, cur.Right)
			}
		}
		res = append(res, level)
	}
	return res
}

func Array2DToString(array [][]int) string {
	if len(array) == 0 {
		return "[]"
	}
	arr2str := func(arr []int) string {
		res := "["
		for i := 0; i < len(arr); i++ {
			res += fmt.Sprint(arr[i])
			if i != len(arr)-1 {
				res += ","
			}
		}
		return res + "]"
	}
	res := make([]string, len(array))
	for i, arr := range array {
		res[i] = arr2str(arr)
	}
	return strings.Join(strings.Fields(fmt.Sprint(res)), ",")
}

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
	node := root
	for node != nil {
		if p.Val < node.Val && q.Val < node.Val {
			node = node.Left
		} else if p.Val > node.Val && q.Val > node.Val {
			node = node.Right
		} else {
			return node
		}
	}
	return nil
}

func main() {
	nums := []int{6, 2, 8, 0, 4, 7, 9, null, null, 3, 5}
	root := buildTree(nums)
	p, q := &TreeNode{Val: 2}, &TreeNode{Val: 8}
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(lowestCommonAncestor(root, p, q).Val)

	q = &TreeNode{Val: 4}
	fmt.Println(lowestCommonAncestor(root, p, q).Val)
}

代码2: 递归

package main

import (
	"fmt"
	"strings"
)

const null = -1 << 31

type TreeNode struct {
	Val   int
	Left  *TreeNode
	Right *TreeNode
}

func buildTree(nums []int) *TreeNode {
	if len(nums) == 0 {
		return nil
	}
	root := &TreeNode{Val: nums[0]}
	Queue := []*TreeNode{root}
	idx := 1
	for idx < len(nums) {
		node := Queue[0]
		Queue = Queue[1:]
		if nums[idx] != null {
			node.Left = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Left)
		}
		idx++
		if idx < len(nums) && nums[idx] != null {
			node.Right = &TreeNode{Val: nums[idx]}
			Queue = append(Queue, node.Right)
		}
		idx++
	}
	return root
}

func levelOrder(root *TreeNode) [][]int {
	res := [][]int{}
	if root == nil {
		return res
	}
	Queue := []*TreeNode{root}
	for len(Queue) > 0 {
		level := []int{}
		n := len(Queue)
		for i := 0; i < n; i++ {
			cur := Queue[0]
			Queue = Queue[1:]
			level = append(level, cur.Val)
			if cur.Left != nil {
				Queue = append(Queue, cur.Left)
			}
			if cur.Right != nil {
				Queue = append(Queue, cur.Right)
			}
		}
		res = append(res, level)
	}
	return res
}

func Array2DToString(array [][]int) string {
	if len(array) == 0 {
		return "[]"
	}
	arr2str := func(arr []int) string {
		res := "["
		for i := 0; i < len(arr); i++ {
			res += fmt.Sprint(arr[i])
			if i != len(arr)-1 {
				res += ","
			}
		}
		return res + "]"
	}
	res := make([]string, len(array))
	for i, arr := range array {
		res[i] = arr2str(arr)
	}
	return strings.Join(strings.Fields(fmt.Sprint(res)), ",")
}

func lowestCommonAncestor(root, p, q *TreeNode) *TreeNode {
    if p.Val < root.Val && q.Val < root.Val {
        return lowestCommonAncestor(root.Left, p, q)
    } else if p.Val > root.Val && q.Val > root.Val {
        return lowestCommonAncestor(root.Right, p, q)
    } else {
        return root
    }
}

func main() {
	nums := []int{6, 2, 8, 0, 4, 7, 9, null, null, 3, 5}
	root := buildTree(nums)
	p, q := &TreeNode{Val: 2}, &TreeNode{Val: 8}
	fmt.Println(Array2DToString(levelOrder(root)))
	fmt.Println(lowestCommonAncestor(root, p, q).Val)

	q = &TreeNode{Val: 4}
	fmt.Println(lowestCommonAncestor(root, p, q).Val)
}

输出:

[[6],[2,8],[0,4,7,9],[3,5]]

6

2


🌟 每日一练刷题专栏 🌟

持续,努力奋斗做强刷题搬运工!

👍 点赞,你的认可是我坚持的动力! 

🌟 收藏,你的青睐是我努力的方向! 

评论,你的意见是我进步的财富!  

 主页:https://hannyang.blog.youkuaiyun.com/ 

Rust每日一练 专栏

(2023.5.16~)更新中...

Golang每日一练 专栏

(2023.3.11~)更新中...

Python每日一练 专栏

(2023.2.18~2023.5.18)暂停更

C/C++每日一练 专栏

(2023.2.18~2023.5.18)暂停更

Java每日一练 专栏

(2023.3.11~2023.5.18)暂停更

评论 3
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hann Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值