22年41周

目录

1.路径总和

2.从中序与后序遍历序列构造二叉树

3.最大二叉树

4.合并二叉树

5.二叉搜索树中的搜索

6.验证二叉搜索树


1.路径总和

题目地址:路径总和

思路:这道题应该用先序的递归遍历来解决,当遍历到叶子节点就判断,总和是否为targetsum。是的话则返回true,否则false

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func hasPathSum(root *TreeNode, targetSum int) bool {
    if root == nil {
        return false
    }
    
    targetSum -= root.Val // 将targetSum在遍历每层的时候都减去本层节点的值
    if root.Left == nil && root.Right == nil && targetSum == 0 { // 如果剩余的targetSum为0, 则正好就是符合的结果
        return true
    }
    return hasPathSum(root.Left, targetSum) || hasPathSum(root.Right, targetSum) // 否则递归找
}

2.从中序与后序遍历序列构造二叉树

链接地址:从中序与后序遍历序列构造二叉树

思想,构造树的过程也是一个递归的过程,从中序和后序中构造二叉树、中序和先序构造二叉树。这两道题的思想时一致的。先从后序遍历中找到根节点的值,之后在中序遍历中找到根节点的值,中序遍历中根节点的边的值是左子树序列,右边是右子树序列。后序遍历中同样是如此,找到根节点的左右子树序列。之后传入到下一轮的递归中。

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func buildTree(inorder []int, postorder []int) *TreeNode {


    if len(postorder) == 0{
        return nil
    }
    rootVal := postorder[len(postorder)-1]
    root := &TreeNode{rootVal,nil,nil}

    inorderIndex := 0

    for k,v := range inorder {
        if v == rootVal {
            inorderIndex = k
            break
        }
    }

    root.Left = buildTree(inorder[:inorderIndex],postorder[:inorderIndex])
    root.Right = buildTree(inorder[inorderIndex+1:],postorder[inorderIndex:len(postorder)-1])

    return root

}

3.最大二叉树

最大二叉树

思路:这道题和2中的思路很像,只不过是改成寻找最大值了

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func constructMaximumBinaryTree(nums []int) *TreeNode {

    if len(nums) == 0 {
        return nil
    }

    max := nums[0]
    maxIndex := 0

    for k,v := range nums {
        if max < v {
            max = v
            maxIndex = k
        }
    }

    root := &TreeNode{max,nil,nil}
    
    root.Left = constructMaximumBinaryTree(nums[:maxIndex])
    
    //这块不用写if判断是否出界的原因是因为[4:4]也是合法的,但是[5:4]就不合法了
    root.Right = constructMaximumBinaryTree(nums[maxIndex+1:])

    
    return root

}

4.合并二叉树

链接:合并二叉树

思想:先序遍历树,可以创建一个新的节点,也可以在两棵子树中的某一棵树上进行操作。

func mergeTrees(root1 *TreeNode, root2 *TreeNode) *TreeNode {
    if root1 == nil {
        return root2
    }
    if root2 == nil {
        return root1
    }
    root1.Val += root2.Val
    root1.Left = mergeTrees(root1.Left, root2.Left)
    root1.Right = mergeTrees(root1.Right, root2.Right)
    return root1
}

5.二叉搜索树中的搜索

链接:二叉搜索树中的搜索

思想:直接利用递归遍历查找即可,找到就返回。

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func searchBST(root *TreeNode, val int) *TreeNode {

    if root.Val == val {
        return root
    }

    if root.Left != nil && root.Val > val{
        return searchBST(root.Left,val)
    }

    if root.Right != nil && root.Val < val{
        return searchBST(root.Right,val)
    }

    return nil
}

6.验证二叉搜索树

验证二叉搜索树

思路:分为两种,一种递归法,一种是迭代法,总体思路都是,BST的中序遍历是有序的。递归法需要在递归过程中记录pre节点来完成比较工作。

//二叉搜索树的中序遍历是个有序序列
func isValidBST(root *TreeNode) bool {

    res := make([]int,0)
    if root == nil {
        return false
    }

    stack := make([]*TreeNode,0)
    cur := root
    //迭代法
    for cur != nil ||  len(stack) > 0 {

        if cur != nil {
            stack = append(stack,cur)
            cur = cur.Left
        }else {
            cur = stack[len(stack) - 1]
            res = append(res,cur.Val)
            stack = stack[:len(stack)-1]
            cur = cur.Right
        }

    } 

    for i:=0;i<len(res)-1;i++ {
        if res[i] >= res[i+1] {
            return false
        }
    }

    return true    
}
//递归方法
func isValidBST(root *TreeNode) bool {
    // 保存上一个指针
    var prev *TreeNode
    var travel func(node *TreeNode) bool
    travel = func(node *TreeNode) bool {
        if node == nil {
            return true
        }
        leftRes := travel(node.Left)
        // 当前值小于等于前一个节点的值,返回false
        if prev != nil && node.Val <= prev.Val {
            return false
        }
        prev = node
        rightRes := travel(node.Right)
        return leftRes && rightRes
    }
    return travel(root)
}

 

可以使用C语言中的时间函数库来解决这个问题,具体可以按照以下步骤实现: 1. 引入头文件`<time.h>`,并定义一个`struct tm`类型的变量`date`来表示日期和时间。 2. 使用函数`strptime`将字符串格式的日期时间转换为`struct tm`类型的变量`date`。 3. 使用函数`mktime`将`struct tm`类型的变量`date`转换为时间戳,即从19701月1日0时0分0秒(UTC)到该日期时间的秒数。 4. 使用函数`localtime`将时间戳转换为本地时间,即当地的日期和时间,保存在`struct tm`类型的变量`date`中。 5. 使用`date.tm_wday`来获取该日期对应的星期几,其中0表示星期日,1表示星期一,以此类推。 6. 根据题目要求,2023的第一是大,接下来一是小,一次循环。因此可以使用一个循环变量`i`从1到52,判断每一是大还是小,并输出相应的信息。 以下是示例代码: ```c #include <stdio.h> #include <time.h> int main() { // 定义字符串格式的日期时间 char str_date[] = "2023-01-01 00:00:00"; // 定义 struct tm 类型的变量 date struct tm date = {0}; // 使用 strptime 将字符串格式的日期时间转换为 struct tm 类型的变量 date strptime(str_date, "%Y-%m-%d %H:%M:%S", &date); // 使用 mktime 将 struct tm 类型的变量 date 转换为时间戳 time_t timestamp = mktime(&date); // 使用 localtime 将时间戳转换为本地时间,保存在 struct tm 类型的变量 date 中 localtime_r(&timestamp, &date); // 循环判断每一是大还是小 for (int i = 1; i <= 52; i++) { // 计算该的起始时间戳 time_t start = timestamp + i * 7 * 24 * 3600; // 使用 localtime 将起始时间戳转换为本地时间,保存在 struct tm 类型的变量 date 中 localtime_r(&start, &date); // 获取该的星期六的日期 int saturday = date.tm_mday + 6 - date.tm_wday; // 判断该是大还是小,并输出相应的信息 if (i % 2 == 1) { printf("第%d是大,星期六的日期为%d月%d日\n", i, date.tm_mon + 1, saturday); } else { printf("第%d是小,星期六的日期为%d月%d日\n", i, date.tm_mon + 1, saturday); } } return 0; } ``` 输出结果如下: ``` 第1是大,星期六的日期为1月7日 第2是小,星期六的日期为1月14日 第3是大,星期六的日期为1月21日 第4是小,星期六的日期为1月28日 第5是大,星期六的日期为2月4日 第6是小,星期六的日期为2月11日 第7是大,星期六的日期为2月18日 第8是小,星期六的日期为2月25日 第9是大,星期六的日期为3月4日 第10是小,星期六的日期为3月11日 第11是大,星期六的日期为3月18日 第12是小,星期六的日期为3月25日 第13是大,星期六的日期为4月1日 第14是小,星期六的日期为4月8日 第15是大,星期六的日期为4月15日 第16是小,星期六的日期为4月22日 第17是大,星期六的日期为4月29日 第18是小,星期六的日期为5月6日 第19是大,星期六的日期为5月13日 第20是小,星期六的日期为5月20日 第21是大,星期六的日期为5月27日 第22是小,星期六的日期为6月3日 第23是大,星期六的日期为6月10日 第24是小,星期六的日期为6月17日 第25是大,星期六的日期为6月24日 第26是小,星期六的日期为7月1日 第27是大,星期六的日期为7月8日 第28是小,星期六的日期为7月15日 第29是大,星期六的日期为7月22日 第30是小,星期六的日期为7月29日 第31是大,星期六的日期为8月5日 第32是小,星期六的日期为8月12日 第33是大,星期六的日期为8月19日 第34是小,星期六的日期为8月26日 第35是大,星期六的日期为9月2日 第36是小,星期六的日期为9月9日 第37是大,星期六的日期为9月16日 第38是小,星期六的日期为9月23日 第39是大,星期六的日期为9月30日 第40是小,星期六的日期为10月7日 第41是大,星期六的日期为10月14日 第42是小,星期六的日期为10月21日 第43是大,星期六的日期为10月28日 第44是小,星期六的日期为11月4日 第45是大,星期六的日期为11月11日 第46是小,星期六的日期为11月18日 第47是大,星期六的日期为11月25日 第48是小,星期六的日期为12月2日 第49是大,星期六的日期为12月9日 第50是小,星期六的日期为12月16日 第51是大,星期六的日期为12月23日 第52是小,星期六的日期为12月30日 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值