代码随想录Day39 198.打家劫舍,213.打家劫舍II,337.打家劫舍 III。

news2024/12/27 6:06:53

1.打家劫舍

力扣题目链接(opens new window)

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

  • 示例 1:
  • 输入:[1,2,3,1]
  • 输出:4

解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。   偷窃到的最高金额 = 1 + 3 = 4 。

  • 示例 2:
  • 输入:[2,7,9,3,1]
  • 输出:12 解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。   偷窃到的最高金额 = 2 + 9 + 1 = 12 。

提示:

  • 0 <= nums.length <= 100
  • 0 <= nums[i] <= 400

思路

大家如果刚接触这样的题目,会有点困惑,当前的状态我是偷还是不偷呢?

仔细一想,当前房屋偷与不偷取决于 前一个房屋和前两个房屋是否被偷了。

所以这里就更感觉到,当前状态和前面状态会有一种依赖关系,那么这种依赖关系都是动规的递推公式。

当然以上是大概思路,打家劫舍是dp解决的经典问题,接下来我们来动规五部曲分析如下:

  1. 确定dp数组(dp table)以及下标的含义

dp[i]:考虑下标i(包括i)以内的房屋,最多可以偷窃的金额为dp[i]

  1. 确定递推公式

决定dp[i]的因素就是第i房间偷还是不偷。

如果偷第i房间,那么dp[i] = dp[i - 2] + nums[i] ,即:第i-1房一定是不考虑的,找出 下标i-2(包括i-2)以内的房屋,最多可以偷窃的金额为dp[i-2] 加上第i房间偷到的钱。

如果不偷第i房间,那么dp[i] = dp[i - 1],即考 虑i-1房,(注意这里是考虑,并不是一定要偷i-1房,这是很多同学容易混淆的点

然后dp[i]取最大值,即dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);

  1. dp数组如何初始化

从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]

从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);

  1. 确定遍历顺序

dp[i] 是根据dp[i - 2] 和 dp[i - 1] 推导出来的,那么一定是从前到后遍历!

  1. 举例推导dp数组

以示例二,输入[2,7,9,3,1]为例。

198.打家劫舍

红框dp[nums.size() - 1]为结果。

总结

打家劫舍是DP解决的经典题目,这道题也是打家劫舍入门级题目,后面我们还会变种方式来打劫的。

动态规划

public class rob_houses {
    public int rob1(int[] nums) {
        if (nums == null || nums.length == 0) return 0;//如果数组nums为空或长度为0,返回0,因为没有房子可以抢劫。
        if (nums.length == 1) return nums[0];//如果数组长度为1,返回数组中唯一的元素,因为只有一个房子可以抢劫。
        int[] dp = new int[nums.length];//初始化dp数组,其中dp[i]表示在前i+1个房子中能抢到的最大金额。
        dp[0] = nums[0];//dp[0]设置为nums[0],即第一个房子的金额。
        dp[1] = Math.max(dp[0], nums[1]);//dp[1]设置为nums[0]和nums[1]中的最大值,因为盗贼可以选择抢劫第一个或第二个房子,但不能同时抢。
        for (int i = 2; i < nums.length; i++) {//从第三个房子开始,每个房子的抢劫金额是前两个房子中较大金额与当前房子金额之和的最大值。这是因为盗贼不能抢劫相邻的房子。
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        return dp[nums.length - 1];//返回dp数组的最后一个元素,即所有房子中能抢到的最大金额。
    }
  
}
  • 时间复杂度:O(n),其中n是数组nums的长度。这是因为我们只需要遍历一次数组。
  • 空间复杂度:O(n),因为我们需要一个大小为n的数组dp来存储每个阶段的最大抢劫金额。

滚动数组

public class rob_houses {
    public int rob2(int[] nums) {
        int len = nums.length;
        if (len == 0) return 0;//如果数组nums长度为0,返回0。
        else if (len == 1) return nums[0];//如果数组长度为1,返回nums[0]。
        else if (len == 2) return Math.max(nums[0],nums[1]);//如果数组长度为2,返回nums[0]和nums[1]中的最大值。
        int[] result = new int[3]; //使用三个变量result[0]、result[1]和result[2]来存储连续三个房子的最大抢劫金额。
        result[0] = nums[0];
        result[1] = Math.max(nums[0],nums[1]);//从第三个房子开始,更新result数组,其中result[2]是result[0] + nums[i]和result[1]中的最大值。
        for(int i=2;i<len;i++){
            result[2] = Math.max(result[0]+nums[i],result[1]);
            result[0] = result[1];
            result[1] = result[2];
        }
        return result[2];//返回result[2],即所有房子中能抢到的最大金额。
    }
}
  • 时间复杂度:O(n),与方法1相同,只需要遍历一次数组。
  • 空间复杂度:O(1),因为我们只使用了固定数量的变量(三个变量result[0]result[1]result[2])。
public class rob_houses {
    public int rob3(int[] nums) {
        if (nums.length == 1)  {//如果数组nums只有一个元素,返回该元素。
            return nums[0];
        }
        int[] dp = new int[2];//初始化两个变量dp[0]和dp[1],分别存储前两个房子的最大抢劫金额。
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0],nums[1]);
        int res = 0;
        for (int i = 2; i < nums.length; i++) {//从第三个房子开始,使用变量res来存储当前房子的最大抢劫金额,它是前一个房子的最大金额(dp[1])和前两个房子的金额之和(dp[0] + nums[i])中的最大值。
            res = Math.max((dp[0] + nums[i]) , dp[1] );
            dp[0] = dp[1];//更新dp[0]和dp[1]为下一个循环做准备。
            dp[1] = res;
        }
        return dp[1];//返回dp[1],即所有房子中能抢到的最大金额。
    }
}
  • 时间复杂度:O(n),与方法1和方法2相同,只需要遍历一次数组。
  • 空间复杂度:O(1),因为我们只使用了固定数量的变量(两个变量dp[0]dp[1])。

2.打家劫舍II

力扣题目链接(opens new window)

你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 。

给定一个代表每个房屋存放金额的非负整数数组,计算你 在不触动警报装置的情况下 ,能够偷窃到的最高金额。

示例 1:

  • 输入:nums = [2,3,2]

  • 输出:3

  • 解释:你不能先偷窃 1 号房屋(金额 = 2),然后偷窃 3 号房屋(金额 = 2), 因为他们是相邻的。

  • 示例 2:

  • 输入:nums = [1,2,3,1]

  • 输出:4

  • 解释:你可以先偷窃 1 号房屋(金额 = 1),然后偷窃 3 号房屋(金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。

  • 示例 3:

  • 输入:nums = [0]

  • 输出:0

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 1000

思路

这道题目和198.打家劫舍 (opens new window)是差不多的,唯一区别就是成环了。

对于一个数组,成环的话主要有如下三种情况:

  • 情况一:考虑不包含首尾元素

213.打家劫舍II

  • 情况二:考虑包含首元素,不包含尾元素

213.打家劫舍II1

  • 情况三:考虑包含尾元素,不包含首元素

213.打家劫舍II2

注意我这里用的是"考虑",例如情况三,虽然是考虑包含尾元素,但不一定要选尾部元素! 对于情况三,取nums[1] 和 nums[3]就是最大的。

而情况二 和 情况三 都包含了情况一了,所以只考虑情况二和情况三就可以了

分析到这里,本题其实比较简单了。 剩下的和198.打家劫舍 (opens new window)就是一样的了。

总结

成环之后还是难了一些的, 不少题解没有把“考虑房间”和“偷房间”说清楚。

这就导致大家会有这样的困惑:情况三怎么就包含了情况一了呢? 本文图中最后一间房不能偷啊,偷了一定不是最优结果。

所以我在本文重点强调了情况一二三是“考虑”的范围,而具体房间偷与不偷交给递推公式去抉择。

这样大家就不难理解情况二和情况三包含了情况一了。

public class rob_housesII {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0)//如果nums数组为空或为null,返回0,因为没有房子可以抢劫。
            return 0;
        int len = nums.length;
        if (len == 1)//如果数组长度为1,返回数组中唯一的元素,因为只有一个房子可以抢劫。
            return nums[0];
        return Math.max(robAction(nums, 0, len - 1), robAction(nums, 1, len));//如果数组长度大于1,盗贼有两个选择:抢劫第一个房子或者跳过第一个房子。rob方法计算这两种选择的最大值,并返回较大的那个。robAction(nums, 0, len - 1)计算从第一个房子开始抢劫的情况,即包括第一个房子在内的最大抢劫金额。robAction(nums, 1, len)计算从第二个房子开始抢劫的情况,即不包括第一个房子在内的最大抢劫金额。
    }
    int robAction(int[] nums, int start, int end) {
        int x = 0, y = 0, z = 0;//x、y和z三个变量用于存储动态规划的状态。x表示不包括当前房子的最大抢劫金额。y是x的前一个状态,用于在循环中更新x。z表示包括当前房子的最大抢劫金额。
        for (int i = start; i < end; i++) {//循环从start索引开始,到end索引之前结束。在每次迭代中,y被更新为z的前一个状态,即x。z被更新为y(不包括当前房子)和x + nums[i](包括当前房子)中的最大值。x被更新为y,即z的前一个状态。
            y = z;
            z = Math.max(y, x + nums[i]);
            x = y;
        }
        return z;//循环结束后,z存储了从start到end索引的房子能抢到的最大金额。返回z作为结果。
    }
}
  • 时间复杂度:O(n),其中n是数组nums的长度。这是因为我们只需要遍历一次数组。
  • 空间复杂度:O(1),因为我们只使用了固定数量的变量(三个变量xyz)。

3.打家劫舍 III

力扣题目链接(opens new window)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

337.打家劫舍III

思路

这道题目和 198.打家劫舍 (opens new window),213.打家劫舍II (opens new window)也是如出一辙,只不过这个换成了树。

如果对树的遍历不够熟悉的话,那本题就有难度了。

对于树的话,首先就要想到遍历方式,前中后序(深度优先搜索)还是层序遍历(广度优先搜索)。

本题一定是要后序遍历,因为通过递归函数的返回值来做下一步计算

与198.打家劫舍,213.打家劫舍II一样,关键是要讨论当前节点抢还是不抢。

如果抢了当前节点,两个孩子就不能动,如果没抢当前节点,就可以考虑抢左右孩子(注意这里说的是“考虑”

暴力递归

计算了root的四个孙子(左右孩子的孩子)为头结点的子树的情况,又计算了root的左右孩子为头结点的子树的情况,计算左右孩子的时候其实又把孙子计算了一遍。

记忆化递推

所以可以使用一个map把计算过的结果保存一下,这样如果计算过孙子了,那么计算孩子的时候可以复用孙子节点的结果。

动态规划

在上面两种方法,其实对一个节点 偷与不偷得到的最大金钱都没有做记录,而是需要实时计算。

而动态规划其实就是使用状态转移容器来记录状态的变化,这里可以使用一个长度为2的数组,记录当前节点偷与不偷所得到的的最大金钱。

这道题目算是树形dp的入门题目,因为是在树上进行状态转移,我们在讲解二叉树的时候说过递归三部曲,那么下面我以递归三部曲为框架,其中融合动规五部曲的内容来进行讲解

  1. 确定递归函数的参数和返回值

这里我们要求一个节点 偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组。

其实这里的返回数组就是dp数组。

所以dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

所以本题dp数组就是一个长度为2的数组!

那么有同学可能疑惑,长度为2的数组怎么标记树中每个节点的状态呢?

别忘了在递归的过程中,系统栈会保存每一层递归的参数

如果还不理解的话,就接着往下看,看到代码就理解了哈。

  1. 确定终止条件

在遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回。

这也相当于dp数组的初始化

  1. 确定遍历顺序

首先明确的是使用后序遍历。 因为要通过递归函数的返回值来做下一步计算。

通过递归左节点,得到左节点偷与不偷的金钱。

通过递归右节点,得到右节点偷与不偷的金钱。

  1. 确定单层递归的逻辑

如果是偷当前节点,那么左右孩子就不能偷,val1 = cur->val + left[0] + right[0]; (如果对下标含义不理解就再回顾一下dp数组的含义

如果不偷当前节点,那么左右孩子就可以偷,至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);

最后当前节点的状态就是{val2, val1}; 即:{不偷当前节点得到的最大金钱,偷当前节点得到的最大金钱}

  1. 举例推导dp数组

以示例1为例,dp数组状态如下:(注意用后序遍历的方式推导

最后头结点就是 取下标0 和 下标1的最大值就是偷得的最大金钱

总结

这道题是树形DP的入门题目,通过这道题目大家应该也了解了,所谓树形DP就是在树上进行递归公式的推导。

所以树形DP也没有那么神秘!

只不过平时我们习惯了在一维数组或者二维数组上推导公式,一下子换成了树,就需要对树的遍历方式足够了解!

大家还记不记得我在讲解贪心专题的时候,讲到这道题目:贪心算法:我要监控二叉树! (opens new window),这也是贪心算法在树上的应用。那我也可以把这个算法起一个名字,叫做树形贪心

public class rob_housesIII {
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode() {
        }
        TreeNode(int val) {
            this.val = val;
        }
        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
        public int rob(TreeNode root) {
            if (root == null)//如果当前节点root为空,返回0,因为没有钱可以抢劫。
                return 0;
            int money = root.val;//计算当前节点的金额money,包括当前节点的值和它的孙子节点的值(如果存在)。
            if (root.left != null) {//如果当前节点有左子节点,递归计算左子节点的左子树和右子树的金额,并加到money上。
                money += rob(root.left.left) + rob(root.left.right);
            }
            if (root.right != null) {//如果当前节点有右子节点,递归计算右子节点的左子树和右子树的金额,并加到money上。
                money += rob(root.right.left) + rob(root.right.right);
            }
            return Math.max(money, rob(root.left) + rob(root.right));//计算两种情况:包括当前节点的抢劫金额(money)和不包括当前节点的抢劫金额(递归计算左子树和右子树的金额)。
        }
    
}
  • 时间复杂度:O(4^h),其中h是树的高度。这是因为每个节点都可能递归地计算它的四个孙子节点(左子节点的左右子节点和右子节点的左右子节点)。
  • 空间复杂度:O(h),递归栈的最大深度是树的高度,因为可能需要存储所有递归调用的节点。
public class rob_housesIII {
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode() {
        }
        TreeNode(int val) {
            this.val = val;
        }
        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
        public int rob1(TreeNode root) {
            Map<TreeNode, Integer> memo = new HashMap<>();//它初始化一个HashMap memo来存储已经计算过的节点值,以避免重复计算。
            return robAction(root, memo);
        }
        int robAction(TreeNode root, Map<TreeNode, Integer> memo) {
            if (root == null)
                return 0;//如果当前节点root为空,返回0。
            if (memo.containsKey(root))//如果当前节点已经在memo中,直接返回其值。
                return memo.get(root);
            int money = root.val;//计算当前节点的金额money,包括当前节点的值和它的孙子节点的值(如果存在)。
            if (root.left != null) {//递归计算左子树和右子树的孙子节点的金额,并加到money上。计算两种情况:包括当前节点的抢劫金额(money)和不包括当前节点的抢劫金额(递归计算左子树和右子树的金额)。将计算结果存储在memo中,并返回最大值。
                money += robAction(root.left.left, memo) + robAction(root.left.right, memo);
            }
            if (root.right != null) {
                money += robAction(root.right.left, memo) + robAction(root.right.right, memo);
            }
            int res = Math.max(money, robAction(root.left, memo) + robAction(root.right, memo));
            memo.put(root, res);
            return res;
        }
    
}
  • 时间复杂度:O(n),其中n是树中节点的数量。每个节点只计算一次,但由于记忆化,递归树的每个分支都被缩减。
  • 空间复杂度:O(n),需要存储所有节点的计算结果,以及递归栈的最大深度,最坏情况下是树的高度。
public class rob_housesIII {
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode() {
        }
        TreeNode(int val) {
            this.val = val;
        }
        TreeNode(int val, TreeNode left, TreeNode right) {
            this.val = val;
            this.left = left;
            this.right = right;
        }
       
        public int rob3(TreeNode root) {
            int[] res = robAction1(root);//它调用robAction1并返回两种情况中的最大值。
            return Math.max(res[0], res[1]);
        }
        int[] robAction1(TreeNode root) {//robAction1是辅助方法,它返回一个包含两个元素的数组:第一个元素是不抢劫当前节点时的最大金额,第二个元素是抢劫当前节点时的最大金额。
            int res[] = new int[2];
            if (root == null)//如果当前节点root为空,返回一个初始化数组。
                return res;
            int[] left = robAction1(root.left);//递归计算左子树和右子树的抢劫金额。对于当前节点,计算不抢劫当前节点时的最大金额(即取左右子树抢劫金额的最大值之和)。计算抢劫当前节点时的最大金额(即当前节点的值加上左右子树不抢劫时的最大金额)。返回一个包含这两个值的数组。
            int[] right = robAction1(root.right);
            res[0] = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
            res[1] = root.val + left[0] + right[0];
            return res;
        }
    }
}
  • 时间复杂度:O(n),其中n是树中节点的数量。每个节点只计算一次。
  • 空间复杂度:O(h),递归栈的最大深度是树的高度,因为可能需要存储所有递归调用的节点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266203.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

01-linux基础命令

一、linux命令概述 命令 选项 参数命令 &#xff1a;就是命令名&#xff1b;选项&#xff1a;一般以 - 开头 比如&#xff1a;-a -p -r 等扩展命令的功能&#xff1b;参数&#xff1a;描述命令的目标&#xff0c;如我们要打开一个文件的话&#xff0c;参数就是要打开的文件名…

MATLAB符号计算-初步认识符号对象

1.1自顶向下的程序设计方法 【例1-1】列主元Guass消去法解方程组 a[2 -3 5 -1;1 4 2 -3;-2 4 -3 -7;8 0 -2 1]; b[3 7 -1 8]; sLZYguass(a,b) 代码还有问题&#xff0c;x11.1913,x21.1157,x30.8114,x40.0923 学长帮忙修改过&#xff1a; 反思&#xff1a; length()、size(…

支持向量机入门指南:从原理到实践

目录 1 支持向量机的基本概念 1.2 数学表达 2 间隔与支持向量 2.1 几何间隔 2.2 支持向量的概念 2.3 规范化超平面 2.4 支持向量的深入分析 2.4.1 支持向量的特征 2.4.2 支持向量的作用 2.4.3 支持向量的代数表示 2.5 KKT条件 3 最优化问题 3.1 问题的形成 3.2 规…

快速汇总Word表格

示例需求&#xff1a;Word文档中的有多个表格&#xff0c;其中最后一个表格为汇总表格&#xff0c;其他的为数据表格&#xff0c;如下图中左侧所示。 现在需要根据Category1和Category2&#xff0c;在数据表格中查找&#xff0c;如果找到匹配行&#xff0c;那么 为数据表中改…

OSCP课后练习-tcpdump

本篇文章旨在为网络安全渗透测试行业OSCP考证教学。通过阅读本文&#xff0c;读者将能够对tcpdump日志分析关键信息过滤有一定了解 1、下载练习分析文件 wget https://www.offensive-security.com/pwk-online/password_cracking_filtered.pcap2、查看分析文件所有内容 sudo t…

Linux快速入门-Linux的常用命令

Linux的常用命令 1. Linux的终端与工作区1.1 终端概述1.2 切换终端 2. Shell语言解释器2.1 Shell概述 3. 用户登录与身份切换3.1 su 命令3.2 sudo 命令 4. 文件、目录操作命令4.1 pwd 命令4.2 cd 命令4.3 ls 命令4.3.1 ls 指令叠加使用 4.4 mkdir 命令4.5 rmdir 命令4.6 cp 命令…

ASP.NET Web应用程序出现Maximum request length exceeded报错

一、问题描述 在ASP.NET的web应用中&#xff0c;导出数据时出现500 - Internal server error.Maximum request length exceeded。 二、原因分析 这个错误通常出现在Web应用程序中&#xff0c;表示客户端发送的HTTP请求的长度超过了服务器配置的最大请求长度限制。这可能是因为…

【JDBC】使用原生JDBC,数据量很大且内存空间较小的情况下,JavaHeap溢出

文章目录 使用原生JDBC&#xff0c;数据量很大且内存空间较小的情况下&#xff0c;JavaHeap非常容易溢出问题背景java.lang.OutOfMemoryError: Java heap space错误分析解决方案1. **优化数据库查询**2. **调整 JVM 堆内存**3. **批量处理数据**4. **线程池优化** 总结**Result…

uniapp 微信小程序 数据空白展示组件

效果图 html <template><view class"nodata"><view class""><image class"nodataimg":src"$publicfun.locaAndHttp()?localUrl:$publicfun.httpUrlImg(httUrl)"mode"aspectFit"></image>&l…

12.26 学习卷积神经网路(CNN)

完全是基于下面这个博客来进行学习的&#xff0c;感谢&#xff01; ​​【深度学习基础】详解Pytorch搭建CNN卷积神经网络LeNet-5实现手写数字识别_pytorch cnn-CSDN博客 基于深度神经网络DNN实现的手写数字识别&#xff0c;将灰度图像转换后的二维数组展平到一维&#xff0c;…

【团标】《信息工程造价政务信息化项目造价评估方法》(TCQAE11021-2023)-费用标准解读系列33

《信息工程造价政务信息化项目造价评估方法》&#xff08;TCQAE11021-2023&#xff09;是中国电子质量管理协会2023年发布&#xff0c;2023年12月16日开始实施的标准&#xff08;了解更多可直接关注我们咨询&#xff09;。该标准适用于政务信息化项目的造价评估&#xff0c;政务…

mybatisplu设置自动填充

/*** mybatisplus的自动化填充*/public class JboltMetaObjectHandler implements MetaObjectHandler {Overridepublic void insertFill(MetaObject metaObject) {LocalDateTime now LocalDateTime.now(ZoneId.of("Asia/Shanghai"));this.strictInsertFill(metaObje…

音视频入门基础:MPEG2-TS专题(23)——通过FFprobe显示TS流每个packet的信息

一、引言 通过FFprobe命令&#xff1a; ffprobe -of json -show_packets XXX.ts 可以显示TS流/TS文件每个packet&#xff08;也称为数据包或多媒体包&#xff09;的信息&#xff1a; 对于TS流&#xff0c;上述的“packet”&#xff08;数据包或多媒体包&#xff09;是指&…

Linux电源管理——CPU Hotplug 流程

目录 一、相关概念 二、基本原理 三、代码分析 1、CPU_ON 2、CPU_OFF References Linux Version&#xff1a;linux-5.4.239 一、相关概念 在单核操作系统中&#xff0c;操作系统只需管理一个CPU&#xff0c;当系统有任务需要执行时&#xff0c;所有的任务会在该CPU的就绪…

探索数据的艺术:R语言与Origin的完美结合

探索数据的艺术&#xff1a;R语言与Origin的完美结合 R语言统计分析与可视化从入门到精通内容简介获取方式 Origin绘图深度解析&#xff1a;科研数据的可视化艺术内容简介获取方式 R语言统计分析与可视化从入门到精通 内容简介 本书循序渐进、深入讲解了R语言数据统计分析与应…

python基础训练之元组的基本操作

主页包含元组基础知识点 【练习要求】 针对于元组的知识点进行常用的创建、定义、查询元素、查看元组长度等操作。效果实现如下 (注&#xff1a;特别要注意一下切片的用法) #创建元组的两种方法 T1 () T2 tuple() #定义一个元组并存储数据张三, 李四, 王五 T3 (张三, 李四…

选煤厂可视化技术助力智能化运营

通过图扑 HT 可视化搭建智慧选煤厂管理平台&#xff0c;优化了选煤生产流程&#xff0c;提高了资源利用率和安全性&#xff0c;助力企业实现智能化运营和可持续发展目标。

C语言基础:指针(数组指针与指针数组)

数组指针与指针数组 数组指针 概念&#xff1a;数组指针是指向数组的指针&#xff0c;本质上还是指针 特点&#xff1a; 先有数组&#xff0c;后有指针 它指向的是一个完整的数组 一维数组指针&#xff1a; 语法&#xff1a; 数据类型 (*指针变量名)[行容量][列容量]; 案…

接口测试Day03-postman断言关联

postman常用断言 注意&#xff1a;不需要手敲&#xff0c;点击自动生成 断言响应状态码 Status code&#xff1a;Code is 200 //断言响应状态码为 200 pm.test("Status code is 200", function () {pm.response.to.have.status(200); });pm: postman的实例 test() …

01- 三自由度串联机械臂位置分析

三自由度串联机械臂如下图所示&#xff08;d180mm&#xff0c;L1100mm&#xff0c;L280mm&#xff09;&#xff0c;利用改进DH法建模&#xff0c;坐标系如下所示&#xff1a; 利用改进DH法建模&#xff0c;该机器人的DH参数表如下所示&#xff1a; 对该机械臂进行位置分析&…