当前位置: 首页 > news >正文

50.【必备】二分答案法与相关题目

本文的网课内容学习自B站左程云老师的算法详解课程,旨在对其中的知识进行整理和分享~

网课链接:算法讲解051【必备】二分答案法与相关题目_哔哩哔哩_bilibili

一.爱吃香蕉的珂珂

题目:爱吃香蕉的珂珂

算法原理

  • 整体思路
    • 这是一个二分查找算法的应用,目的是找到珂珂吃香蕉的最小速度k,使得她能在h小时内吃完所有香蕉。
  • 确定搜索范围
    • 下限l:珂珂吃香蕉的速度最小为1根/小时,所以l = 1
    • 上限r:通过遍历piles数组,找到香蕉堆中香蕉数量最多的那一堆,即r = Math.max(r, pile)。因为如果珂珂以这个最大堆的香蕉数量为速度,肯定能在h小时内吃完所有香蕉(最保守的估计)。
  • 二分查找过程
    • while (l <= r)循环中进行二分查找。
    • 计算中间速度m:使用m = l+((r - l)>>1)来计算中间速度,这样做可以避免整数溢出(相比于m=(l + r)/2)。
    • 检查速度是否达标
      • 调用f(piles, m)函数来计算以速度m吃香蕉需要花费的小时数。如果f(piles, m)<=h,说明速度m是达标的。
        • 在这种情况下,将当前速度m记录为可能的答案(ans = m),然后将搜索范围缩小到左半部分(r = m - 1),因为要找最小的达标速度。
      • 如果f(piles, m)>h,说明速度m不达标,需要将搜索范围缩小到右半部分(l = m + 1),即增加吃香蕉的速度。
  • 计算以特定速度吃完香蕉的小时数(f函数)
    • 遍历piles数组中的每一堆香蕉。
    • 对于每一堆香蕉pile,计算以速度speed吃完这堆香蕉需要的小时数。使用(pile + speed - 1)/speed来向上取整计算小时数。例如,如果pile = 5speed = 3,则(5 + 3 - 1)/3 = 7/3 = 2(向上取整)。
    • 将每一堆香蕉所需的小时数累加起来,最后返回总小时数ans

代码实现

// 爱吃香蕉的珂珂
// 珂珂喜欢吃香蕉。这里有 n 堆香蕉,第 i 堆中有 piles[i] 根香蕉
// 警卫已经离开了,将在 h 小时后回来。
// 珂珂可以决定她吃香蕉的速度 k (单位:根/小时)
// 每个小时,她将会选择一堆香蕉,从中吃掉 k 根
// 如果这堆香蕉少于 k 根,她将吃掉这堆的所有香蕉,然后这一小时内不会再吃更多的香蕉
// 珂珂喜欢慢慢吃,但仍然想在警卫回来前吃掉所有的香蕉。
// 返回她可以在 h 小时内吃掉所有香蕉的最小速度 k(k 为整数)
// 测试链接 : https://leetcode.cn/problems/koko-eating-bananas/
public class Code01_KokoEatingBananas {// 时间复杂度O(n * log(max)),额外空间复杂度O(1)public static int minEatingSpeed(int[] piles, int h) {// 最小且达标的速度,范围[l,r]int l = 1;int r = 0;for (int pile : piles) {r = Math.max(r, pile);}// [l,r]不停二分int ans = 0;int m = 0;while (l <= r) {// m = (l + r) / 2m = l + ((r - l) >> 1);if (f(piles, m) <= h) {// 达标!// 记录答案,去左侧二分ans = m;// l....m....r// l..m-1r = m - 1;} else {// 不达标l = m + 1;}}return ans;}// 香蕉重量都在piles// 速度就定成speed// 返回吃完所有的香蕉,耗费的小时数量public static long f(int[] piles, int speed) {long ans = 0;for (int pile : piles) {// (a/b)结果向上取整,如果a和b都是非负数,可以写成(a+b-1)/b// "讲解032-位图"讲了这种写法,不会的同学可以去看看// 这里不再赘述ans += (pile + speed - 1) / speed;}return ans;}}

二.画匠问题

题目:分割数组的最大值

算法原理

  • 整体思路
    • 这是一个二分查找算法的应用,目的是找到将数组nums分成k个非空连续子数组时,使得子数组各自和的最大值最小的那个值。
  • 确定二分查找的范围
    • 左边界l初始化为0,表示子数组和的最大值最小可能为0(虽然实际情况中每个数都是非负整数,所以最小为数组中的最小值,但这里从0开始方便计算)。
    • 右边界r初始化为数组nums的所有元素之和sum,这是子数组和的最大值的最大可能值(即将整个数组作为一个子数组)。
  • 二分查找过程
    • while (l <= r)循环中进行二分查找。
    • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,这样可以避免整数溢出。
    • 检查中间值是否达标
      • 调用f(nums, m)函数,该函数计算在子数组和的最大值不超过m的情况下,数组nums可以被划分成的子数组数量。
      • 如果need = f(nums, m)<=k,说明将子数组和的最大值限制为m时,划分出的子数组数量不超过k个,这个m是达标的。
        • 在这种情况下,将当前的m记录为可能的答案(ans = m),然后将搜索范围缩小到左半部分(r = m - 1),因为要找最小的达标值。
      • 如果need = f(nums, m)>k,说明将子数组和的最大值限制为m时,划分出的子数组数量超过了k个,这个m不达标,需要将搜索范围缩小到右半部分(l = m + 1),即增加子数组和的最大值的限制。
  • 计算划分数量(f函数)
    • 初始化parts = 1表示至少有一个子数组,sum = 0用于记录当前子数组的累加和。
    • 遍历数组arr中的每个元素num
      • 如果num > limit,说明这个元素本身就大于限制值limit,那么按照要求无法划分,直接返回Integer.MAX_VALUE
      • 如果sum + num > limit,说明当前子数组的累加和加上这个元素会超过限制值limit,则需要新划分一个子数组,所以parts加1,并且将sum更新为num(开始新的子数组累加)。
      • 如果sum + num <= limit,则将这个元素加入当前子数组,sum += num
    • 最后返回划分出的子数组数量parts

代码实现

// 分割数组的最大值(画匠问题)
// 给定一个非负整数数组 nums 和一个整数 m
// 你需要将这个数组分成 m 个非空的连续子数组。
// 设计一个算法使得这 m 个子数组各自和的最大值最小。
// 测试链接 : https://leetcode.cn/problems/split-array-largest-sum/
public class Code02_SplitArrayLargestSum {// 时间复杂度O(n * log(sum)),额外空间复杂度O(1)public static int splitArray(int[] nums, int k) {long sum = 0;for (int num : nums) {sum += num;}long ans = 0;// [0,sum]二分for (long l = 0, r = sum, m, need; l <= r;) {// 中点mm = l + ((r - l) >> 1);// 必须让数组每一部分的累加和 <= m,请问划分成几个部分才够!need = f(nums, m);if (need <= k) {// 达标ans = m;r = m - 1;} else {l = m + 1;}}return (int) ans;}// 必须让数组arr每一部分的累加和 <= limit,请问划分成几个部分才够!// 返回需要的部分数量public static int f(int[] arr, long limit) {int parts = 1;int sum = 0;for (int num : arr) {if (num > limit) {return Integer.MAX_VALUE;}if (sum + num > limit) {parts++;sum = num;} else {sum += num;}}return parts;}}

三.机器人跳跃问题

题目:机器人跳跃问题

算法原理

  • 整体思路
    • 这是一个二分查找算法的应用,目的是找到机器人开始游戏时所需的最小能量值,使得机器人能够成功从编号为0的建筑到达编号为N的建筑,并且在过程中能量值不为负数。
  • 确定二分查找的范围
    • 左边界l初始化为0,表示机器人开始游戏时的最小可能能量值。
    • 右边界r初始化为所有建筑高度中的最大值(通过遍历arr数组得到,r = Math.max(r, arr[i])),这是机器人开始游戏时能量值的最大可能取值(如果初始能量大于所有建筑高度,理论上一定能通关)。
  • 二分查找过程
    • while (l <= r)循环中进行二分查找。
    • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,这种方式可以避免整数溢出。
    • 检查中间值是否达标
      • 调用f(m, max)函数,其中m是当前假设的机器人初始能量值,max是所有建筑的最大高度。该函数用于判断以能量值m开始游戏是否能够成功通关。
      • 如果f(m, max)返回true,说明以能量值m开始游戏是可以通关的。
        • 在这种情况下,将当前的m记录为可能的答案(ans = m),然后将搜索范围缩小到左半部分(r = m - 1),因为要找最小的能通关的能量值。
      • 如果f(m, max)返回false,说明以能量值m开始游戏不能通关,需要将搜索范围缩小到右半部分(l = m + 1),即增加初始能量值。
  • 判断能否通关(f函数)
    • 遍历从1到n的每一座建筑(因为机器人从编号为0的建筑开始,这里从1开始遍历下一个建筑)。
    • 对于每一座建筑i,根据规则计算机器人到达下一座建筑后的能量值。
      • 如果energy <= arr[i],机器人失去arr[i] - energy的能量值,即energy -= arr[i] - energy
      • 如果energy > arr[i],机器人得到energy - arr[i]的能量值,即energy += energy - arr[i]
    • 在每次计算完能量值后进行检查:
      • 如果energy >= max,由于能量值已经超过了所有建筑的最大高度,后面肯定能通关,直接返回true
      • 如果energy < 0,说明能量值变为负数,不能通关,直接返回false
    • 如果成功遍历完所有建筑都没有返回false,则返回true,表示可以通关。

代码实现

// 机器人跳跃问题
// 机器人正在玩一个古老的基于DOS的游戏
// 游戏中有N+1座建筑,从0到N编号,从左到右排列
// 编号为0的建筑高度为0个单位,编号为i的建筑的高度为H(i)个单位
// 起初机器人在编号为0的建筑处
// 每一步,它跳到下一个(右边)建筑。假设机器人在第k个建筑,且它现在的能量值是E
// 下一步它将跳到第个k+1建筑
// 它将会得到或者失去正比于与H(k+1)与E之差的能量
// 如果 H(k+1) > E 那么机器人就失去H(k+1)-E的能量值,否则它将得到E-H(k+1)的能量值
// 游戏目标是到达第个N建筑,在这个过程中,能量值不能为负数个单位
// 现在的问题是机器人以多少能量值开始游戏,才可以保证成功完成游戏
// 测试链接 : https://www.nowcoder.com/practice/7037a3d57bbd4336856b8e16a9cafd71
// 请同学们务必参考如下代码中关于输入、输出的处理
// 这是输入输出处理效率很高的写法
// 提交以下的code,提交时请把类名改成"Main",可以直接通过import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;public class Code03_RobotPassThroughBuilding {public static int MAXN = 100001;public static int[] arr = new int[MAXN];public static int n;public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));StreamTokenizer in = new StreamTokenizer(br);PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));while (in.nextToken() != StreamTokenizer.TT_EOF) {n = (int) in.nval;int l = 0;int r = 0;for (int i = 1; i <= n; i++) {in.nextToken();arr[i] = (int) in.nval;r = Math.max(r, arr[i]);}out.println(compute(l, r, r));}out.flush();out.close();br.close();}// [l,r]通关所需最小能量的范围,不停二分// max是所有建筑的最大高度// 时间复杂度O(n * log(max)),额外空间复杂度O(1)public static int compute(int l, int r, int max) {int m, ans = -1;while (l <= r) {// m中点,此时通关所需规定的初始能量m = l + ((r - l) >> 1);if (f(m, max)) {ans = m;r = m - 1;} else {l = m + 1;}}return ans;}// 初始能量为energy,max是建筑的最大高度,返回能不能通关// 为什么要给定建筑的最大高度?public static boolean f(int energy, int max) {// 注意!// 如果给的能量值很大,那么后续能量增长将非常恐怖// 完全有可能超出long的范围// 所以要在遍历时,一定要加入energy >= max的判断// 一旦能量超过高度最大值,后面肯定通关了,可以提前返回了// 这里很阴for (int i = 1; i <= n; i++) {if (energy <= arr[i]) {energy -= arr[i] - energy;} else {energy += energy - arr[i];}if (energy >= max) {return true;}if (energy < 0) {return false;}}return true;}}

 四.找到第K小的数对距离

题目:找出第 K 小的数对距离

算法原理

  • 整体思路
    • 该算法的目的是在给定的整数数组nums中找到第k小的数对距离。通过二分查找的思想来实现。
  • 排序数组
    • 首先对nums数组进行排序,这是为了方便后续计算数对距离。排序后的数组在计算数对距离时可以利用有序性提高效率,时间复杂度为O(n/log n)。
  • 确定二分查找范围
    • 左边界l初始化为0,表示数对距离的最小值。
    • 右边界r初始化为nums[n - 1] - nums[0],即数组中最大数与最小数的差值,这是数对距离的最大可能值。
  • 二分查找过程
    • while (l <= r)循环中进行二分查找。
    • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,可避免整数溢出。
    • 检查中间值是否符合要求
      • 调用f(nums, m)函数,该函数计算在数对距离不超过m的情况下,数对的数量。
      • 如果cnt = f(nums, m)>=k,说明数对距离不超过m的数对数量不少于k个,这个m可能是第k小的数对距离。
        • 此时将当前的m记录为可能的答案(ans = m),并将搜索范围缩小到左半部分(r = m - 1),因为要找最小的符合要求的值。
      • 如果cnt = f(nums, m)<k,说明数对距离不超过m的数对数量少于k个,这个m不是第k小的数对距离,需要将搜索范围缩小到右半部分(l = m + 1),即增加数对距离的下限。
  • 计算数对数量(f函数)
    • 初始化ans = 0用于记录数对数量。
    • 使用双指针lr遍历数组arr
      • 对于每个l,通过移动r使得arr[r + 1] - arr[l] <= limit
      • 当满足这个条件时,在arr[l...r]范围内的数与arr[l]组成的数对距离都不超过limit,这样的数对数量为r - l,将其累加到ans中。
    • 最后返回ans,即数对距离不超过limit的数对数量。

代码实现

import java.util.Arrays;// 找出第K小的数对距离
// 数对 (a,b) 由整数 a 和 b 组成,其数对距离定义为 a 和 b 的绝对差值。
// 给你一个整数数组 nums 和一个整数 k
// 数对由 nums[i] 和 nums[j] 组成且满足 0 <= i < j < nums.length
// 返回 所有数对距离中 第 k 小的数对距离。
// 测试链接 : https://leetcode.cn/problems/find-k-th-smallest-pair-distance/
public class Code04_FindKthSmallestPairDistance {// 时间复杂度O(n * log(n) + log(max-min) * n),额外空间复杂度O(1)public static int smallestDistancePair(int[] nums, int k) {int n = nums.length;Arrays.sort(nums);int ans = 0;// [0, 最大-最小],不停二分for (int l = 0, r = nums[n - 1] - nums[0], m, cnt; l <= r;) {// m中点,arr中任意两数的差值 <= mm = l + ((r - l) >> 1);// 返回数字对的数量cnt = f(nums, m);if (cnt >= k) {ans = m;r = m - 1;} else {l = m + 1;}}return ans;}// arr中任意两数的差值 <= limit// 这样的数字配对,有几对?public static int f(int[] arr, int limit) {int ans = 0;// O(n)for (int l = 0, r = 0; l < arr.length; l++) {// l......r r+1while (r + 1 < arr.length && arr[r + 1] - arr[l] <= limit) {r++;}// arr[l...r]范围上的数差值的绝对值都不超过limit// arr[0...3]// 0,1// 0,2// 0,3ans += r - l;}return ans;}}

五.同时运行N台电脑的最长时间

题目:同时运行 N 台电脑的最长时间

算法原理

一.maxRunTime1(单纯的二分答案法)
  • 整体思路
    • 这是一个二分查找算法的应用,目的是找到能让num台电脑同时运行的最长时间。
  • 计算电量总和(maxRunTime1函数部分)
    • 首先计算所有电池电量的总和sum,通过遍历数组arr,将每个电池的电量x累加到sum中。这个总和是电脑能运行时间的一个上限值,因为假设所有电量都给一台电脑用,这就是最长运行时间的理论最大值。
  • 二分查找过程(maxRunTime1函数部分)
    • 确定二分查找的范围:左边界l = 0,表示电脑运行时间的最小值;右边界r = sum,即前面计算出的所有电池电量总和,是运行时间的最大可能值。
    • while (l <= r)循环中进行二分查找。
    • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,这种方式可以避免整数溢出。
    • 检查中间值是否可行:调用f1(arr, num, m)函数,该函数判断让num台电脑共同运行m分钟是否可行。
      • 如果f1(arr, num, m)返回true,说明m分钟是可行的运行时间。
        • 在这种情况下,将当前的m记录为可能的答案(ans = m),然后将搜索范围扩大到右半部分(l = m + 1),因为要找最大的可行运行时间。
      • 如果f1(arr, num, m)返回false,说明m分钟不可行,需要将搜索范围缩小到左半部分(r = m - 1)。
  • 判断可行性(f1函数部分)
    • 初始化碎片电量总和sum = 0
    • 遍历电池电量数组arr中的每个电池电量x
      • 如果x > time,说明这个电池电量足够让一台电脑单独运行time分钟。此时可以用这个电池给一台电脑供电,所以num(表示还需要供电的电脑台数)减1。
      • 如果x <= time,这个电池属于碎片电池,将其电量x累加到sum中。
    • 在每次迭代过程中,检查sum >= (long) num * time是否成立。
      • 如果成立,说明碎片电量足够给剩余的num台电脑供电time分钟,所以返回true
      • 如果不成立,说明电量不足,返回false
二.maxRunTime2(二分答案法 + 增加分析(贪心))
  • 整体思路
    • 这个算法基于二分答案法,并结合贪心思想来求解能让num台电脑同时运行的最长时间。
  • 前期计算与初步判断(maxRunTime2函数部分)
    • 首先遍历电池电量数组arr,计算出电池电量的最大值max和所有电池电量的总和sum
    • 然后进行一个初步判断:如果sum > (long) max * num,根据贪心思想,这意味着最终的供电时间一定在>= max的范围内。因为所有电池电量总和足够大,当供电时间达到最大电池电量max时,所有电池都可看作是“碎片拼接”的情况。在这种情况下,直接计算sum / num作为最终的供电时间并返回。
  • 二分查找过程(maxRunTime2函数部分,当sum <= (long) max * num时)
    • 确定更精细的二分查找范围:左边界l = 0,右边界r = max。相比于maxRunTime1[0, sum]的范围,这个范围更精细,能减少二分查找的次数。
    • while (l <= r)循环中进行二分查找。
    • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,避免整数溢出。
    • 检查中间值是否可行:调用f2(arr, num, m)函数,该函数判断让num台电脑共同运行m分钟是否可行。
      • 如果f2(arr, num, m)返回true,说明m分钟是可行的运行时间。
        • 将当前的m记录为可能的答案(ans = m),然后将搜索范围扩大到右半部分(l = m + 1),因为要找最大的可行运行时间。
      • 如果f2(arr, num, m)返回false,说明m分钟不可行,需要将搜索范围缩小到左半部分(r = m - 1)。
  • 判断可行性(f2函数部分)
    • 初始化碎片电量总和sum = 0
    • 遍历电池电量数组arr中的每个电池电量x
      • 如果x > time,说明这个电池电量足够让一台电脑单独运行time分钟,此时可以用这个电池给一台电脑供电,所以num(表示还需要供电的电脑台数)减1。
      • 如果x <= time,这个电池属于碎片电池,将其电量x累加到sum中。
    • 在每次迭代过程中,检查sum >= (long) num * time是否成立。
      • 如果成立,说明碎片电量足够给剩余的num台电脑供电time分钟,所以返回true
      • 如果不成立,说明电量不足,返回false

代码实现

// 同时运行N台电脑的最长时间
// 你有 n 台电脑。给你整数 n 和一个下标从 0 开始的整数数组 batteries
// 其中第 i 个电池可以让一台电脑 运行 batteries[i] 分钟
// 你想使用这些电池让 全部 n 台电脑 同时 运行。
// 一开始,你可以给每台电脑连接 至多一个电池
// 然后在任意整数时刻,你都可以将一台电脑与它的电池断开连接,并连接另一个电池,你可以进行这个操作 任意次
// 新连接的电池可以是一个全新的电池,也可以是别的电脑用过的电池
// 断开连接和连接新的电池不会花费任何时间。
// 注意,你不能给电池充电。
// 请你返回你可以让 n 台电脑同时运行的 最长 分钟数。
// 测试链接 : https://leetcode.cn/problems/maximum-running-time-of-n-computers/
public class Code05_MaximumRunningTimeOfNComputers {// 单纯的二分答案法// 提交时把函数名改为maxRunTime// 时间复杂度O(n * log(sum)),额外空间复杂度O(1)public static long maxRunTime1(int num, int[] arr) {long sum = 0;for (int x : arr) {sum += x;}long ans = 0;// [0, sum],不停二分for (long l = 0, r = sum, m; l <= r;) {// m中点,让num台电脑共同运行m分钟,能不能做到m = l + ((r - l) >> 1);if (f1(arr, num, m)) {ans = m;l = m + 1;} else {r = m - 1;}}return ans;}// 让num台电脑共同运行time分钟,能不能做到public static boolean f1(int[] arr, int num, long time) {// 碎片电量总和long sum = 0;for (int x : arr) {if (x > time) {num--;} else {// x <= time,是碎片电池sum += x;}if (sum >= (long) num * time) {// 碎片电量 >= 台数 * 要求return true;}}return false;}// 二分答案法 + 增加分析(贪心)// 提交时把函数名改为maxRunTime// 时间复杂度O(n * log(max)),额外空间复杂度O(1)public static long maxRunTime2(int num, int[] arr) {int max = 0;long sum = 0;for (int x : arr) {max = Math.max(max, x);sum += x;}// 就是增加了这里的逻辑if (sum > (long) max * num) {// 所有电池的最大电量是max// 如果此时sum > (long) max * num,// 说明 : 最终的供电时间一定在 >= max,而如果最终的供电时间 >= max// 说明 : 对于最终的答案X来说,所有电池都是课上讲的"碎片拼接"的概念// 那么寻找 ? * num <= sum 的情况中,尽量大的 ? 即可// 即sum / numreturn sum / num;}// 最终的供电时间一定在 < max范围上// [0, sum]二分范围,可能定的比较粗,虽然不影响,但毕竟是有点慢// [0, max]二分范围!更精细的范围,二分次数会变少int ans = 0;for (int l = 0, r = max, m; l <= r;) {m = l + ((r - l) >> 1);if (f2(arr, num, m)) {ans = m;l = m + 1;} else {r = m - 1;}}return ans;}public static boolean f2(int[] arr, int num, int time) {// 碎片电量总和long sum = 0;for (int x : arr) {if (x > time) {num--;} else {sum += x;}if (sum >= (long) num * time) {return true;}}return false;}}

六.计算等位时间

题目:计算等位时间(谷歌面试题,没找到测试链接,所以使用了对数器来验证)

给定一个数组arr长度为n,表示n个服务员,每服务一个人的时间。
给定一个正数m,表示有m个人等位,如果你是刚来的人,请问你需要等多久?
假设m远远大于n,比如n <= 10^3, m <= 10^9,该怎么做是最优解?

算法原理

  • 整体思路
    • 该算法旨在解决在给定服务员服务时间数组arr和等位人数m的情况下,计算新来的人需要等待多久的问题。提供了两种方法,waitingTime1使用堆模拟,waitingTime2使用二分答案法(最优解)。
  • waitingTime1(堆模拟)算法原理
    • 构建小根堆
      • 创建一个PriorityQueue(小根堆),堆中元素是int[]类型,每个元素表示一个服务员的状态,包含[醒来时间,服务一个客人要多久]
      • 遍历服务员服务时间数组arr,将每个服务员的初始状态[0, arr[i]]加入堆中。
    • 模拟服务过程
      • 对于等位的m个人,每次从堆中取出一个服务员(堆顶元素),这个服务员的醒来时间最短。
      • 该服务员为一个客人服务后,更新其醒来时间(cur[0] += cur[1]),然后再将这个服务员放回堆中。
    • 获取结果
      • 重复上述步骤m次后,堆顶元素的醒来时间就是新来的人需要等待的时间,通过heap.peek()[0]获取。
    • 时间复杂度和空间复杂度
      • 时间复杂度O(mlog n),其中m是等位人数,n是服务员数量。每次从堆中取出或放入元素都需要O(log n)的时间,总共进行m次操作。
      • 空间复杂度为O(n),因为堆中最多存储n个服务员的状态。
  • waitingTime2(二分答案法 - 最优解)算法原理
    • 确定二分查找范围
      • 首先找到服务员服务时间数组arr中的最小值min
      • 二分查找的左边界l = 0,右边界r = min * w,这里的w是等位人数m(代码中变量名使用w可能是一种混淆,实际意义是等位人数m)。
    • 二分查找过程
      • while (l <= r)循环中进行二分查找。
      • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,避免整数溢出。
      • 检查中间值是否满足条件:调用f(arr, m)函数,该函数计算如果每个服务员工作m时间,可以接待的客人数量。如果接待的客人数量f(arr, m) >= w + 1(要接待等位的m个人以及正在服务的1个人),说明这个m时间可能是等待时间。
        • 将当前的m记录为可能的答案(ans = m),然后将搜索范围缩小到左半部分(r = m - 1),因为要找最小的满足条件的时间。
        • 如果f(arr, m) < w + 1,说明m时间不够,将搜索范围扩大到右半部分(l = m + 1)。
    • 计算接待客人数量(f函数)
      • 遍历服务员服务时间数组arr中的每个元素num
      • 计算每个服务员在time时间内可以服务的客人数量(time / num),再加上1(表示当前正在服务的客人),将结果累加到ans中。
    • 时间复杂度和空间复杂度
      • 时间复杂度为O(nlog(min * w)),其中n是服务员数量,min是服务员服务时间的最小值,w是等位人数(m)。每次计算f(arr, m)需要O(n)的时间,二分查找最多需要O(log(min * w))次。
      • 空间复杂度为O(1),因为只使用了常数级别的额外空间。

代码实现

import java.util.PriorityQueue;// 计算等位时间
// 给定一个数组arr长度为n,表示n个服务员,每服务一个人的时间
// 给定一个正数m,表示有m个人等位,如果你是刚来的人,请问你需要等多久?
// 假设m远远大于n,比如n <= 10^3, m <= 10^9,该怎么做是最优解?
// 谷歌的面试,这个题连考了2个月
// 找不到测试链接,所以用对数器验证
public class Code06_WaitingTime {// 堆模拟// 验证方法,不是重点// 如果m很大,该方法会超时// 时间复杂度O(m * log(n)),额外空间复杂度O(n)public static int waitingTime1(int[] arr, int m) {// 一个一个对象int[]// [醒来时间,服务一个客人要多久]PriorityQueue<int[]> heap = new PriorityQueue<>((a, b) -> (a[0] - b[0]));int n = arr.length;for (int i = 0; i < n; i++) {heap.add(new int[] { 0, arr[i] });}for (int i = 0; i < m; i++) {int[] cur = heap.poll();cur[0] += cur[1];heap.add(cur);}return heap.peek()[0];}// 二分答案法// 最优解// 时间复杂度O(n * log(min * w)),额外空间复杂度O(1)public static int waitingTime2(int[] arr, int w) {int min = Integer.MAX_VALUE;for (int x : arr) {min = Math.min(min, x);}int ans = 0;for (int l = 0, r = min * w, m; l <= r;) {// m中点,表示一定要让服务员工作的时间!m = l + ((r - l) >> 1);// 能够给几个客人提供服务if (f(arr, m) >= w + 1) {ans = m;r = m - 1;} else {l = m + 1;}}return ans;}// 如果每个服务员工作time,可以接待几位客人(结束的、开始的客人都算)public static int f(int[] arr, int time) {int ans = 0;for (int num : arr) {ans += (time / num) + 1;}return ans;}// 对数器测试public static void main(String[] args) {System.out.println("测试开始");int N = 50;int V = 30;int M = 3000;int testTime = 20000;for (int i = 0; i < testTime; i++) {int n = (int) (Math.random() * N) + 1;int[] arr = randomArray(n, V);int m = (int) (Math.random() * M);int ans1 = waitingTime1(arr, m);int ans2 = waitingTime2(arr, m);if (ans1 != ans2) {System.out.println("出错了!");}}System.out.println("测试结束");}// 对数器测试public static int[] randomArray(int n, int v) {int[] arr = new int[n];for (int i = 0; i < n; i++) {arr[i] = (int) (Math.random() * v) + 1;}return arr;}}

 七.刀砍毒杀怪兽问题

题目:刀砍毒杀怪兽问题(大厂算法笔试题,没有找到测试连接,所以使用对数器来验证)

怪兽的初始血量是一个整数hp,给出每一回合刀砍和毒杀的数值cuts和poisons
第i回合如果用刀砍,怪兽在这回合会直接损失cuts[i]的血,不再有后续效果
第i回合如果用毒杀,怪兽在这回合不会损失血量,但是之后每回合都损失poisons[i]的血量
并且你选择的所有毒杀效果,在之后的回合都会叠加
两个数组cuts、poisons,长度都是n,代表你一共可以进行n回合
每一回合你只能选择刀砍或者毒杀中的一个动作
如果你在n个回合内没有直接杀死怪兽,意味着你已经无法有新的行动了
但是怪兽如果有中毒效果的话,那么怪兽依然会在血量耗尽的那回合死掉
返回至少多少回合,怪兽会死掉
数据范围 :
1 <= n <= 10^5
1 <= hp <= 10^9
1 <= cuts[i]、poisons[i] <= 10^9

算法原理

  • 整体思路
    • 这个算法主要解决在给定刀砍和毒杀效果数组cutspoisons以及怪兽初始血量hp的情况下,求出至少多少回合怪兽会死掉的问题。提供了两种方法,fast1(基于动态规划,主要用于验证)和fast2(二分答案法,最优解)。
  • fast1(动态规划方法 - 用于验证)算法原理
    • 动态规划状态定义
      • 定义三维数组dpdp[i][r][p]表示在第i个回合,怪兽剩余血量为r,当前中毒效果累计为p时,最少还需要多少回合能杀死怪兽。
    • 递归计算(f1函数)
      • 首先对剩余血量r减去当前中毒效果pr -= p),如果r <= 0,表示怪兽已经死亡,返回已经进行的回合数i + 1
      • 如果已经到了最后一个回合(i == cuts.length),如果p == 0(没有中毒效果),返回Integer.MAX_VALUE表示无法杀死怪兽;如果p!=0,计算还需要多少回合(cuts.length + 1+(r + p - 1)/p)。
      • 如果dp[i][r][p]已经有计算结果,直接返回这个结果。
      • 计算两种选择(刀砍或毒杀)下的最少回合数:
        • 对于刀砍(p1),如果r <= cuts[i],则只需要当前回合就可以杀死怪兽(i + 1),否则递归调用f1函数计算下一个回合的情况(f1(cuts, poisons, i + 1, r - cuts[i], p, dp))。
        • 对于毒杀(p2),递归调用f1函数计算下一个回合的情况(f1(cuts, poisons, i + 1, r, p + poisons[i], dp))。
      • 取刀砍和毒杀两种选择中的最小值作为dp[i][r][p]的值,并返回这个最小值。
    • 时间复杂度和空间复杂度
      • 时间复杂度:由于有三个维度的状态,每个维度的大小分别为cuts.lengthhp + 1sum + 1sumpoisons数组元素之和),所以时间复杂度非常高,在血量较大时会超时。
      • 空间复杂度:需要创建三维数组dp,空间复杂度为O(cuts.length\times(hp + 1)\times(sum + 1))。
  • fast2(二分答案法 - 最优解)算法原理
    • 二分查找范围
      • 左边界l = 1,因为至少需要1回合;右边界r = hp + 1,因为最多需要hp回合(每回合刀砍1点血的极端情况)再加1(保证右边界能被包含在查找范围内)。
    • 二分查找过程
      • while (l <= r)循环中进行二分查找。
      • 计算中间值m:使用m = l+((r - l)>>1)计算中间值,避免整数溢出。
      • 检查中间值是否可行:调用f(cuts, posions, hp, m)函数,该函数判断在m回合内是否能杀死怪兽。
        • 如果f(cuts, posions, hp, m)返回true,说明m回合可以杀死怪兽。将当前的m记录为可能的答案(ans = m),然后将搜索范围缩小到左半部分(r = m - 1),因为要找最小的满足条件的回合数。
        • 如果f(cuts, posions, hp, m)返回false,说明m回合不能杀死怪兽,将搜索范围扩大到右半部分(l = m + 1)。
    • 判断是否能在限制回合内杀死怪兽(f函数)
      • 确定实际参与计算的回合数n,取cuts.lengthlimit(这里的limit就是二分查找中的m)中的较小值。
      • 遍历前n个回合,对于每个回合i
        • 计算本回合对怪兽血量的削减量,取刀砍的削减量cuts[i]和毒杀的削减量(limit - j)*poisons[i]j从1开始计数,表示回合数的偏移量)中的最大值,然后从怪兽血量hp中减去这个削减量(hp -= Math.max((long) cuts[i], (long) (limit - j)*(long) poisons[i]);)。
        • 如果hp <= 0,说明怪兽已经死亡,返回true
      • 如果遍历完所有回合后hp > 0,说明怪兽未死亡,返回false
    • 时间复杂度和空间复杂度
      • 时间复杂度:每次计算f(cuts, posions, hp, m)需要O(n)的时间(ncutspoisons数组的长度),二分查找最多需要O(log(hp))次,所以总的时间复杂度为O(nlog(hp))。
      • 空间复杂度:只使用了常数级别的额外空间,所以空间复杂度为O(1)。

代码实现

// 刀砍毒杀怪兽问题
// 怪兽的初始血量是一个整数hp,给出每一回合刀砍和毒杀的数值cuts和poisons
// 第i回合如果用刀砍,怪兽在这回合会直接损失cuts[i]的血,不再有后续效果
// 第i回合如果用毒杀,怪兽在这回合不会损失血量,但是之后每回合都损失poisons[i]的血量
// 并且你选择的所有毒杀效果,在之后的回合都会叠加
// 两个数组cuts、poisons,长度都是n,代表你一共可以进行n回合
// 每一回合你只能选择刀砍或者毒杀中的一个动作
// 如果你在n个回合内没有直接杀死怪兽,意味着你已经无法有新的行动了
// 但是怪兽如果有中毒效果的话,那么怪兽依然会在血量耗尽的那回合死掉
// 返回至少多少回合,怪兽会死掉
// 数据范围 :
// 1 <= n <= 10^5
// 1 <= hp <= 10^9
// 1 <= cuts[i]、poisons[i] <= 10^9
// 本题来自真实大厂笔试,找不到测试链接,所以用对数器验证
public class Code07_CutOrPoison {// 动态规划方法(只是为了验证)// 目前没有讲动态规划,所以不需要理解这个函数// 这个函数只是为了验证二分答案的方法是否正确的// 纯粹为了写对数器验证才设计的方法,血量比较大的时候会超时// 这个方法不做要求,此时并不需要理解,可以在学习完动态规划章节之后来看看这个函数public static int fast1(int[] cuts, int[] poisons, int hp) {int sum = 0;for (int num : poisons) {sum += num;}int[][][] dp = new int[cuts.length][hp + 1][sum + 1];return f1(cuts, poisons, 0, hp, 0, dp);}// 不做要求public static int f1(int[] cuts, int[] poisons, int i, int r, int p, int[][][] dp) {r -= p;if (r <= 0) {return i + 1;}if (i == cuts.length) {if (p == 0) {return Integer.MAX_VALUE;} else {return cuts.length + 1 + (r + p - 1) / p;}}if (dp[i][r][p] != 0) {return dp[i][r][p];}int p1 = r <= cuts[i] ? (i + 1) : f1(cuts, poisons, i + 1, r - cuts[i], p, dp);int p2 = f1(cuts, poisons, i + 1, r, p + poisons[i], dp);int ans = Math.min(p1, p2);dp[i][r][p] = ans;return ans;}// 二分答案法// 最优解// 时间复杂度O(n * log(hp)),额外空间复杂度O(1)public static int fast2(int[] cuts, int[] poisons, int hp) {int ans = Integer.MAX_VALUE;for (int l = 1, r = hp + 1, m; l <= r;) {// m中点,一定要让怪兽在m回合内死掉,更多回合无意义m = l + ((r - l) >> 1);if (f(cuts, poisons, hp, m)) {ans = m;r = m - 1;} else {l = m + 1;}}return ans;}// cuts、posions,每一回合刀砍、毒杀的效果// hp:怪兽血量// limit:回合的限制public static boolean f(int[] cuts, int[] posions, long hp, int limit) {int n = Math.min(cuts.length, limit);for (int i = 0, j = 1; i < n; i++, j++) {hp -= Math.max((long) cuts[i], (long) (limit - j) * (long) posions[i]);if (hp <= 0) {return true;}}return false;}// 对数器测试public static void main(String[] args) {// 随机测试的数据量不大// 因为数据量大了,fast1方法会超时// 所以在数据量不大的情况下,验证fast2方法功能正确即可// fast2方法在大数据量的情况下一定也能通过// 因为时间复杂度就是最优的System.out.println("测试开始");int N = 30;int V = 20;int H = 300;int testTimes = 10000;for (int i = 0; i < testTimes; i++) {int n = (int) (Math.random() * N) + 1;int[] cuts = randomArray(n, V);int[] posions = randomArray(n, V);int hp = (int) (Math.random() * H) + 1;int ans1 = fast1(cuts, posions, hp);int ans2 = fast2(cuts, posions, hp);if (ans1 != ans2) {System.out.println("出错了!");}}System.out.println("测试结束");}// 对数器测试public static int[] randomArray(int n, int v) {int[] ans = new int[n];for (int i = 0; i < n; i++) {ans[i] = (int) (Math.random() * v) + 1;}return ans;}}

八.总结

二分答案法:

1)估计最终答案可能的范围是什么

2)分析问题的答案给定条件之间的单调性,大部分时候只需要用到自然智慧

3)建立一个f函数,当答案固定的情况下,判断给定的条件是否达标

4)在最终答案可能的范围上不断二分搜索,每次用f函数判断,直到二分结束,找到最合适的答案

核心点:分析单调性、建立f函数

相关文章:

50.【必备】二分答案法与相关题目

本文的网课内容学习自B站左程云老师的算法详解课程&#xff0c;旨在对其中的知识进行整理和分享~ 网课链接&#xff1a;算法讲解051【必备】二分答案法与相关题目_哔哩哔哩_bilibili 一.爱吃香蕉的珂珂 题目&#xff1a;爱吃香蕉的珂珂 算法原理 整体思路 这是一个二分查找算法…...

C# 方法(局部变量和局部常量)

本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 局部变量 和第5章介绍的字段…...

MQTT 协议与 HTTP 协议的区别

在现代的网络通信中&#xff0c;MQTT 协议和 HTTP 协议都扮演着重要的角色&#xff0c;但它们有着不同的特点和适用场景。下面我们就从多个方面来详细探讨它们之间的区别。 一.协议设计理念 1. MQTT 协议 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;即…...

博弈论思维——AI与思维模型【90】

一、定义 博弈论思维模型是一种研究在相互影响的决策情境中&#xff0c;参与者如何通过策略选择来实现自身利益最大化的理论框架。它分析参与者之间的相互作用、策略组合以及由此产生的结果&#xff0c;帮助人们理解在竞争或合作环境下的决策逻辑和行为模式。 二、由来 博弈…...

【Bootstrap V4系列】学习入门教程之 表格(Tables)和画像(Figure)

Bootstrap V4系列 学习入门教程之 表格&#xff08;Tables&#xff09;和画像&#xff08;Figure&#xff09; 表格&#xff08;Tables&#xff09;一、Examples二、Table head options 表格头选项三、Striped rows 条纹行四、Bordered table 带边框的表格五、Borderless table…...

第 3 篇:有序的世界:有序表 (TreeMap/TreeSet) 的概念与优势

上一篇我们探讨了哈希表如何以牺牲顺序为代价换取极致的平均速度。然而&#xff0c;在现实世界的许多应用中&#xff0c;数据的有序性不仅是锦上添花&#xff0c;甚至是核心需求。想象一下&#xff1a; 你需要显示一个按价格排序的商品列表。你需要找到某个时间点之前或之后的…...

VulnHub-DC-2靶机

主机发现 sudo arp-scan -l 以sudo管理员权限扫描本地活动ip地址 Interface: eth0, type: EN10MB, MAC: 08:00:27:22:46:4f, IPv4: 192.168.252.230 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.252.6 4c:5f:70:74:3c:3b …...

论文笔记(八十三)STACKGEN: Generating Stable Structures from Silhouettes via Diffusion

STACKGEN: Generating Stable Structures from Silhouettes via Diffusion 文章概括摘要I. INTRODUCTIONII. 相关工作A. 从直觉物理学学习稳定性B. 用于姿态生成的扩散模型C. 自动化顺序装配 III. 方法A. 用于 S E ( 3 ) SE(3) SE(3)积木姿态生成的扩散模型B. 模型架构C. 数据生…...

论文阅读笔记——TesserAct: Learning 4D Embodied World Models

TesserAct 论文 采用RGB-DN&#xff08;RGB深度法线&#xff09; 作为 4D 场景中间表示&#xff0c;由此建模 4D 场景&#xff0c;比纯 2D 视频更准确地建模 3D 几何结构。相比现有的 4D 视频生成&#xff0c;优化速度快&#xff0c;收敛好&#xff0c;且首次从当前帧和文本描述…...

变转速振动信号分析处理与故障诊断算法模块

变转速振动信号分析处理与故障诊断算法模块&#xff0c;作为信号处理算法工具箱的主要功能模块&#xff0c;形成了以变转速振动信号分析处理与故障诊断算法模块的经典算法模型&#xff0c;可应用于各类关键机械部件&#xff08;轴承、齿轮、转子等&#xff09;的信号分析、故障…...

每日算法-250502

每日算法 - 2025.05.02 记录一下今天刷的几道 LeetCode 算法题。 3191. 使二进制数组全部等于 1 的最少操作次数 I 题目 思路 贪心 解题过程 遍历数组 nums。当我们遇到 nums[i] 时&#xff1a; 如果 nums[i] 是 1&#xff0c;我们不需要进行操作&#xff0c;因为目标是全 …...

如何在纯C中实现类、继承和多态(小白友好版)

基本实现原理 /* 通过结构体函数指针模拟类 */ typedef struct {// 成员变量int x; // 成员方法&#xff08;函数指针&#xff09; void (*print)(void* self); } MyClass;/* 成员函数实现 */ void my_print(void* self) {MyClass* obj (MyClass*)self;p…...

AE/PR插件 转场创建大师专业版 Transition Master Pro v2.0.2 Win+使用教程

Transition Master Pro v2.0.2是一款原生转场插件&#xff0c;专为Adobe Premiere Pro和After Effects设计。它提供了创建、导出和销售自己的转场效果&#xff0c;或从一个庞大的转场预设库中选择。使用Transition Master Pro v2.0.2&#xff0c;您可以快速轻松地创建令人惊叹的…...

[Linux]从零开始的STM32MP157 Buildroot根文件系统构建

一、前言 在前面的教程中&#xff0c;教了大家如何移植一个LInux的内核并且正确启动&#xff0c;我们发现Linux内核在启动后会出现一个错误&#xff0c;提示我们没有找到根文件系统。那么什么是根文件系统呢&#xff1f;之前我们使用Ubuntu编译了STM32MP157的TF-A,UBOOT,LINUX内…...

阿里云服务器 篇五(加更):短链服务网站:添加反垃圾邮件功能

文章目录 系列文章(可选)更新YOURLS版本安装 Compliance 插件安装 Phishtank-2.0 插件(可选)安装 httpBL 插件样例网站(不推荐)使用谷歌解决方案更多系列文章 阿里云服务器 篇一:申请和初始化 阿里云服务器 篇二:搭建静态网站 阿里云服务器 篇三:提交搜索引擎收录 阿…...

状压 DP 详解

文章目录 简介做法洛谷 P1171 简介 状压 DP 其实约等于一个 DP 的小技巧&#xff0c;一般应用在处理一个或多个集合的问题中&#xff08;因为状压 DP 的下标就是一个集合&#xff09;&#xff0c;而且在 n n n 太大的时候建议不要使用这种方法。&#xff08;如果你不懂&#…...

多模态大模型轻量化探索-视觉大模型SAM(Segment Anything Model)

往期&#xff0c;笔者基于LLava的数据对齐训练&#xff0c;搞了一个Reyes多模态大模型&#xff0c;并且看了些多模态大模型&#xff0c;相关开源的多模态大模型如&#xff1a;KimiVL、Internvl、QwenVL等&#xff0c;其视觉编码器的尺寸都比较大&#xff0c;如&#xff1a;Moon…...

数据分析_问题/优化

1 报表开发 1.1 数据问题 (1) 数据易错 问题描述 ①数据整合困难:数据来源多样、格式差异大,整合时处理不当易丢错数据. ②计算逻辑复杂:开发人员对复杂计算逻辑的理解产生偏差,会导致计算结果不准. 解决方案 ①建立数据标准,统一修正字段命名、数据类型、日期格式等 ②加强…...

我的stm32驱动电机驱动着突然就卡死程序死机了是为什么

电源不稳定或干扰 电机启动电流冲击&#xff1a;电机运行时可能导致电源电压跌落&#xff0c;影响STM32稳定性。需检查电源滤波电容、使用独立电源或增加稳压模块 地线干扰&#xff1a;电机与MCU共地时&#xff0c;高频噪声可能通过地线耦合&#xff0c;需采用隔离电路或磁耦芯…...

使用 Java 实现一个简单且高效的任务调度框架

目录 一、任务调度系统概述 &#xff08;一&#xff09;任务调度的目标 &#xff08;二&#xff09;任务调度框架的关键组成 二、任务状态设计 &#xff08;一&#xff09;任务状态流转设计 &#xff08;二&#xff09;任务表设计&#xff08;SQL&#xff09; 三、单机任…...

Git 完整教程:初学者分步指南

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; Git 是一个分布式版本控制系统&#xff0c;可以帮助开发人员跟踪代码更改、与他人协作以及高效管理软件项目。无论您是初学者还是正在提升…...

数字智慧方案5856丨智慧环保综合解决方案(50页PPT)(文末有下载方式)

资料解读&#xff1a;智慧环保综合解决方案 详细资料请看本解读文章的最后内容。 随着城市化进程的加速和环境问题的日益严峻&#xff0c;智慧环保成为提升城市环境管理水平的重要手段。本文将对智慧环保综合解决方案进行详细解读&#xff0c;探讨其在实际应用中的需求、解决…...

VBA快速合并多列单元格

实例需求&#xff1a;工作表中第3行到第5行有如下图所示的数据表&#xff0c;为了方便展示&#xff0c;隐藏了部分列&#xff0c;实际数据为从C列到DO列。 现需要合并第3行和第4行相同内容的单元格&#xff0c;如第10行到第12行所示。 示例代码如下。 Sub MergeDemo()Dim dicM…...

区块链+IoT:创新场景落地背后的技术攻坚战

物联网&#xff08;IoT&#xff09;与区块链技术作为两大颠覆性技术&#xff0c;正通过深度融合推动各行各业的数字化转型。物联网通过连接海量设备实现数据互通与智能化管理&#xff0c;而区块链凭借去中心化、不可篡改和可追溯的特性&#xff0c;为物联网的安全性、隐私保护和…...

自动化测试项目2 --- 比特纵横 [软件测试实战 Java 篇]

目录 项目介绍 项目源码 库地址 项目功能测试 1. 自动化实施步骤 1.1 编写测试用例 1.2 自动化测试脚本开发 1.2.1 配置相关环境, 添加依赖 1.2.2 代码编写 2. 编写自动化脚本过程问题总结 2.1 Actons 方法的使用 2.2 等待的使用 2.3 页面操作 项目性能测试 1. 进…...

【学习笔记】深入理解Java虚拟机学习笔记——第1章 走进Java

第1章 走进Java 1.1 概述 Java成功的原因 1>一次编写到处运行 2>内存管理安全&#xff0c;自动回收 3>运行时编译 4>强大成熟的第三方库 1.2 Java技术体系 1>Java技术体系组成&#xff1a; -Java语言 -Java虚拟机实现 -class文件格式 -Java类库API -第三方J…...

JavaScript性能优化实战之运行时性能优化

在 JavaScript 开发中,运行时性能优化是确保网页响应迅速和流畅的重要环节。优化运行时性能不仅能提高用户体验,还能在高并发的情况下保证应用的稳定性。本文将细化几个常见的 JavaScript 运行时性能优化策略,帮助你提高代码执行效率。 1️⃣ 避免不必要的内存分配和释放 J…...

走进AI的奇妙世界:探索历史、革命与未来机遇

2022年11月30日&#xff0c;ChatGPT的横空出世像一枚深水炸弹&#xff0c;掀起了全球范围的AI狂潮。但这场革命并非偶然——它背后是80年AI发展史的厚积薄发。从图灵的哲学思辨到深度学习的技术突破&#xff0c;再到生成式AI的“涌现”时刻&#xff0c;AI正以惊人的速度模糊人机…...

用c 编写的笔记搜索程序

{XXX文本记录} 文本记录格式 xxx 搜索词条 #include <stdio.h> #include <string.h> #include <stdlib.h>int main(void){FILE *ffopen("help.txt","r");if(fNULL){perror("file");return -1;}char nr[2000];f…...

鼎讯信通 智能通信干扰设备:多频段多模态信号压制解决方案

在万物互联时代&#xff0c;通信安全已成为现代社会的核心基础设施防护重点。面对日益复杂的电磁环境挑战&#xff0c;新一代智能通信干扰设备通过技术创新实现了信号压制能力的革命性突破。本文将深入解析该设备的八大核心功能与技术特性&#xff0c;展现其在商业通信保障、工…...

软件测试概念

这里写目录标题 需求开发模型软件生命周期瀑布模型螺旋模型增量模型、迭代模型敏捷模型Scrum 测试模型V模型W模型&#xff08;双V模型&#xff09; 需求 用户需求&#xff1a;没有经过合理的评估&#xff0c;通常就是一句话 软件需求&#xff1a;是开发人员和测试人员执行工作…...

数据库性能杀手与调优实践

目录 前言一、索引缺失引发的全表扫描灾难1.现象与影响2.优化策略 二、SELECT * 的隐性成本1.危害分析2.优化实践 三、分页查询的性能陷阱1.深度分页问题2.优化方案对比 四、执行计划分析方法论1.关键指标解读2.典型劣化模式识别 五、综合优化最佳实践总结 前言 在数据库应用开…...

初始化列表详解

1.类中包含以下成员&#xff0c;必须放在初始化列表位置进行初始化&#xff1a; 1. 引用成员变量 2.const成员变量 3. 自定义类型成员(且该类没有默认构造函数时 ) 2. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序&#xff0c;与其在初始化列表中的先后次序无关…...

【CVE-2025-1094】:PostgreSQL 14.15 SQL注入漏洞导致的RCE_ 利用代码和分析

目标 PostgreSQL 14.15BeyondTrust Privileged Remote Access (PRA) 和 Remote Support (RS) 软件受影响的版本:使用PostgreSQL 14.15及其版本的BeyondTrust产品Explain CVE-2025-1094 是 PostgreSQL 14.15 版本的 psql 交互式工具中发现的 SQL 注入漏洞。由于输入值的验证不…...

【验证技能】VIP项目大总结

VIP项目快做一段落了&#xff0c;历时一年半&#xff0c;也该要一个大汇总。 VIP简介 VIP开发流程 VIP难点 进程同步 打拍插入不同bit位宽数据问题。 动态升降lane VIP做的不好的地方和改进想法 各层之间交互 testsuite两端关键 所有层的实现架构不统一 VIP经验 ** 架构…...

MyBatis 参数处理全解析

在 Java 开发领域&#xff0c;MyBatis 作为一款优秀的持久层框架&#xff0c;凭借其简洁的设计和强大的功能&#xff0c;受到了广大开发者的青睐。而参数处理作为 MyBatis 中一个至关重要的环节&#xff0c;掌握好它能让我们更高效地使用 MyBatis 进行数据库操作。本文将全面深…...

【自然语言处理与大模型】使用Xtuner进行QLoRA微调实操

本文首先对Xtuner这一微调框架进行简单的介绍。手把手演示如何使用Xtuner对模型进行微调训练&#xff0c;包括数据准备、训练命令执行及训练过程中的监控技巧。最后&#xff0c;在完成微调之后&#xff0c;本文还将介绍如何对微调结果进行简单对话测试。 一、Xtuner微调框架 X…...

2023华为od统一考试B卷【二叉树中序遍历】

前言 博主刷的华为机考题&#xff0c;代码仅供参考&#xff0c;因为没有后台数据&#xff0c;可能有没考虑到的情况 如果感觉对你有帮助&#xff0c;请点点关注点点赞吧&#xff0c;谢谢你&#xff01; 题目描述 思路 0.用Character数组存储树&#xff0c;index下标的左右…...

Midjourney 绘画 + AI 配音:组合玩法打造爆款短视频!

一、引言:AI 重构短视频创作范式 在某短视频工作室的深夜剪辑室里,资深编导正在为一条古风剧情视频发愁:预算有限无法实拍敦煌场景,人工绘制分镜耗时 3 天,配音演员档期排到一周后。而使用 Midjourney 生成敦煌壁画风格的场景图仅需 15 分钟,AI 配音工具实时生成多角色台…...

敏感词 v0.25.1 新特性之返回匹配词,修正 tags 标签

开源项目 敏感词核心 https://github.com/houbb/sensitive-word 敏感词控台 https://github.com/houbb/sensitive-word-admin 版本特性 大家好&#xff0c;我是老马。 敏感词以前在实现的时候&#xff0c;没有返回底层实际匹配的词&#xff0c;有时候问题排查非常耗费时间。 …...

【多线程】六、基于阻塞队列的生产者消费者模型

文章目录 Ⅰ. 生产者消费者模型的概念Ⅱ. 生产者消费者模型的优点Ⅲ. 基于阻塞队列的生产者消费者模型MakefileBlock_queue.hpptask.hpptest.cppⅣ. 如何理解提高了效率❓❓❓Ⅰ. 生产者消费者模型的概念 ​ 生产者消费者模型是一种常见的并发模式,用于解决生产者和消费者之间…...

解决Flutter项目中Gradle构建Running Gradle task ‘assembleDebug‘卡顿问题的终极指南

解决Flutter项目中Gradle构建Running Gradle task ‘assembleDebug‘卡顿问题的终极指南 前言 在开发Flutter应用时,经常会遇到Gradle构建卡在Running Gradle task assembleDebug阶段的问题。本文将分享如何通过配置华为云镜像和使用自定义脚本下载依赖的方法解决这些问题。…...

IntelliJ IDEA 保姆级使用教程

文章目录 一、创建项目二、创建模块三、创建包四、创建类五、编写代码六、运行代码注意 七、IDEA 常见设置1、主题2、字体3、背景色 八、IDEA 常用快捷键九、IDEA 常见操作9.1、类操作9.1.1、删除类文件9.1.2、修改类名称注意 9.2、模块操作9.2.1、修改模块名快速查看 9.2.2、导…...

从此,K8S入门0门槛!

前言 当你想要入门K8S的时候&#xff0c;往往会被各种概念搞的晕乎乎的&#xff0c;什么API Server&#xff0c;Scheduler&#xff0c;Controller manager&#xff0c;Etcd&#xff0c;Pod&#xff0c;Kubelet&#xff0c;kube-proxy&#xff0c;deployment…… 哪怕你使用了…...

vue2和vue3组件如何监听子组件生命周期

在 Vue 中监听子组件的生命周期是一个常见需求&#xff0c;但 Vue 官方并不直接推荐这么做&#xff0c;因为这会打破组件的封装性。但在**一些特定场景&#xff08;如自动化监控、封装逻辑复用&#xff09;**下仍是有意义的。 下面分别讲解 Vue 2 和 Vue 3 中如何监听 子组件的…...

如何用Python绘制两个圆之间的8条公切线

引言 在几何学中&#xff0c;两圆之间存在多种类型的公共切线。本文将通过Python代码演示如何绘制两个同心圆&#xff08;半径分别为1.0和3.0&#xff09;之间的8条公切线&#xff0c;并解释相关数学原理与代码实现细节。 环境准备 import matplotlib.pyplot as plt import …...

会话历史管理——持久化

​​需求场景​​​​推荐方案​​​​理由​​中小企业级应用&#xff0c;需复杂查询MySQL/PostgreSQL事务支持完善&#xff0c;开发成本低海量数据高并发写入Cassandra水平扩展性强&#xff0c;写入性能高非结构化历史数据快速检索MongoDB灵活存储&#xff0c;内置全文检索本…...

C++之IO流

目录 一、C语言的输入与输出 二、流是什么 三、CIO流 3.1、C标准IO流 3.2、C文件IO流 四、stringstream的简单介绍 一、C语言的输入与输出 C语言中我们用到的最频繁的输入输出方式就是scanf ()与printf()。 scanf(): 从标准输入设备(键盘)读取数据&#xff0c;并将值存放…...

maven install时报错:【无效的目标发行版: 17】

在很多次运行项目前的maven install时&#xff0c;我总是遇到无效的目标发行版: 17的问题&#xff0c;解决过之后就又忘了怎么解决&#xff0c;浪费了很多时间。。 今天把他总结一下&#xff0c;如图报错&#xff1a; 解决方法 注意&#xff1a; 如果只想解决这个项目的问题…...

开闭原则(OCP)

非常棒的问题&#xff01;&#x1f50d; 开闭原则&#xff08;OCP, Open/Closed Principle&#xff09;是软件设计的核心原则之一&#xff0c;下面我将从定义、意义、优劣分析、Python示例和结构图五个方面完整解析给你。 &#x1f9e0; 什么是开闭原则&#xff1f; 开闭原则&a…...