LeetCode刷题之HOT100之打家劫舍Ⅲ

2024 7/13 七月就要过去一半了,伴随着蝉鸣,酷暑被窗户隔离,我坐在凳子上,有一只蚊子不愿意放过我。

1、题目描述

在这里插入图片描述

2、算法分析

前面做过打家劫舍Ⅱ,今天来做打家劫舍Ⅲ,小偷也是越来越聪明了,意识到房子的排列类似二叉树,这小偷之前大概率是程序员,我就说吧,计算机就业就是这么广。JAVA炒粉、JAVA烧烤、JAVA外卖、JAVA探花也是应运而生。
Anyway,让我们来分析这题。
这题啊数据结构就是二叉树,只不过除了根节点,其他父节点就只有一个儿子。两个连着的不能都偷,怎么偷才能偷最多米呢?
算法步骤

  1. 初始化:创建两个哈希表 fg,用于存储每个节点的最大价值(偷或不偷)。
  2. 深度优先搜索(DFS): 对每个节点,首先递归地处理其左子树和右子树。 更新 f[node]:如果偷取当前节点node,则当前节点的价值加上不偷取左右子节点左右子树的最大价值(即 g[node.left]g[node.right])。
    更新 g[node]:不偷取当前节点 node 时,取偷取或不偷取左子节点的较大值加上偷取或不偷取右子节点的较大值(即
    Math.max(f[node.left], g[node.left]) + Math.max(f[node.right],g[node.right]))
  3. 返回结果:在遍历完整棵树后,f[root]g[root]分别表示偷取根节点和不偷取根节点时的最大价值。最终答案取两者中的较大值,即 Math.max(f.getOrDefault(root,0), g.getOrDefault(root, 0))

3、代码

 // f[node]表示偷当前节点node时的最大金额  
    Map<TreeNode, Integer> f = new HashMap<TreeNode, Integer>();
    // g[node]表示不偷当前节点node时的最大金额
    Map<TreeNode, Integer> g = new HashMap<TreeNode, Integer>();

    // 主函数,返回偷窃二叉树能获得的最大金额
    public int rob(TreeNode root) {
        // 执行深度优先搜索来填充f和g的值
        dfs(root);
        // 返回偷或不偷根节点时的较大值,因为小偷可以选择从根节点开始偷或不偷
        return Math.max(f.getOrDefault(root, 0), g.getOrDefault(root, 0));
    }

    // 深度优先搜索函数,用于计算每个节点的f和g值
    public void dfs(TreeNode node){
        // 如果节点为空,则直接返回
        if(node == null){
            return;
        }
        // 递归计算左子树的f和g值
        dfs(node.left);
        // 递归计算右子树的f和g值
        dfs(node.right);
        // 计算当前节点node偷时的最大金额:节点值加上不偷左右子节点时的最大金额
        f.put(node, node.val + g.getOrDefault(node.left, 0) + g.getOrDefault(node.right, 0));
        // 计算当前节点node不偷时的最大金额:左右子节点偷与不偷的较大值之和
        g.put(node, Math.max(f.getOrDefault(node.left, 0), g.getOrDefault(node.left, 0)) + 
        Math.max(f.getOrDefault(node.right, 0), g.getOrDefault(node.right, 0)));
    }

4、复杂度分析

  • 时间复杂度 O(n)
  • 空间复杂度 O(n):由于递归会使用到栈空间,空间代价是 O(n),哈希表的空间代价也是 O(n),故空间复杂度也是 O(n)。

okok,做完了,拜拜啦!

### LeetCode Hot 100 Problems for Practice LeetCode提供了一系列热门练习,这些目被广泛认为对于准备技术面试非常有帮助。以下是部分精选的Hot 100列表: #### 数组与字符串 - **两数之和 (Two Sum)**: 给定一个整数数组`nums`和一个目标值`target`,请你在该数组中找出和为目标值的那两个整数,并返回他们的数组下标[^1]。 ```python def twoSum(nums, target): hashmap = {} for i in range(len(nums)): complement = target - nums[i] if complement in hashmap: return [hashmap[complement], i] hashmap[nums[i]] = i ``` - **移动零 (Move Zeroes)**: 将给定数组中的所有零移到数组末尾,同时保持其他元素顺序不变[^2]. ```python class Solution(object): def moveZeroes(self, nums): slow, fast = 0, 0 n = len(nums) while fast < n: if nums[fast] != 0: nums[slow], nums[fast] = nums[fast], nums[slow] slow += 1 fast += 1 return nums ``` #### 链表操作 - **反转链表 (Reverse Linked List)**: 反转单向链表。 ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def reverseList(head): prev = None curr = head while curr is not None: next_temp = curr.next curr.next = prev prev = curr curr = next_temp return prev ``` #### 动态规划 - **爬楼梯 (Climbing Stairs)**: 计算到达楼顶的方法总数。 ```python def climbStairs(n): if n == 1 or n == 2: return n first, second = 1, 2 for _ in range(3, n + 1): third = first + second first = second second = third return second ``` 这些问涵盖了算法设计的核心概念和技术栈的关键方面,非常适合用来提升编程技能和解决问的能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值