普通视图
全球调查显示:超半数对冲基金涉足加密货币投资
产业链相关人士:谷歌方面最近相继去胜宏科技等国内几大PCB巨头考察
小鹏X9超级增程正式开启预售,35万元起售
知情人士:优步拟与Getir达成合作以拓展土耳其配送市场
多晶硅收储新进展 各方合计出资额可能在200亿元至300亿元
临工重机向港交所提交上市申请
摩根士丹利:苹果在机器人技术与实体AI领域有巨大机遇
微软组建超级智能团队,聚焦医疗诊断等领域
山姆・奥特曼称OpenAI今年年化收入将突破200亿美元,2030年有望达数千亿美元
空管人员短缺,美国多地再次出现航班延误
英国央行维持利率在4%不变,为12月降息奠定基础
世界气象组织:2025年将成为有记录以来第二或第三热年份
谷歌将在未来几周全面上市其最强大的AI芯片Ironwood
月之暗面开源Kimi K2 Thinking模型
特斯拉股东批准马斯克1万亿美元薪酬方案
美股三大指数集体收跌,大型科技股普跌
每日一题-最大化城市的最小电量🔴
给你一个下标从 0 开始长度为 n 的整数数组 stations ,其中 stations[i] 表示第 i 座城市的供电站数目。
每个供电站可以在一定 范围 内给所有城市提供电力。换句话说,如果给定的范围是 r ,在城市 i 处的供电站可以给所有满足 |i - j| <= r 且 0 <= i, j <= n - 1 的城市 j 供电。
-
|x|表示x的 绝对值 。比方说,|7 - 5| = 2,|3 - 10| = 7。
一座城市的 电量 是所有能给它供电的供电站数目。
政府批准了可以额外建造 k 座供电站,你需要决定这些供电站分别应该建在哪里,这些供电站与已经存在的供电站有相同的供电范围。
给你两个整数 r 和 k ,如果以最优策略建造额外的发电站,返回所有城市中,最小电量的最大值是多少。
这 k 座供电站可以建在多个城市。
示例 1:
输入:stations = [1,2,4,5,0], r = 1, k = 2 输出:5 解释: 最优方案之一是把 2 座供电站都建在城市 1 。 每座城市的供电站数目分别为 [1,4,4,5,0] 。 - 城市 0 的供电站数目为 1 + 4 = 5 。 - 城市 1 的供电站数目为 1 + 4 + 4 = 9 。 - 城市 2 的供电站数目为 4 + 4 + 5 = 13 。 - 城市 3 的供电站数目为 5 + 4 = 9 。 - 城市 4 的供电站数目为 5 + 0 = 5 。 供电站数目最少是 5 。 无法得到更优解,所以我们返回 5 。
示例 2:
输入:stations = [4,4,4,4], r = 0, k = 3 输出:4 解释: 无论如何安排,总有一座城市的供电站数目是 4 ,所以最优解是 4 。
提示:
n == stations.length1 <= n <= 1050 <= stations[i] <= 1050 <= r <= n - 10 <= k <= 109
2528. 二分查找+差分数组
[TOC]
思路
由于我们要求的是某个值的最大值,所以我们可以采用 <二分查找> 的方式来“猜”结果。
对于每次猜测,创建函数 $f(c)$ ,返回该数是否合法。
我们可以采用<差分数组>的形式记录差值,差分数组相关内容参考本文补充部分。从左到右遍历,设本次猜的数为 $c$ ,遇到位置为 $i$ 处的电站小于 $c$ ,则在 $\min(i + r, n - 1)$ 处<临时>添加电站,也就是位于 $[i, \min(i + 2 * r, n - 1)]$ 的城市都增加了临时电站的覆盖。若在本次猜测中,剩余可加的电站不足,则返回 $False$,若最后剩余电站数大于等于0,则返回 $True$。
代码
class Solution:
def maxPower(self, stations: List[int], r: int, k: int) -> int:
# 差分数组
diff = defaultdict(int)
n = len(stations)
for i, val in enumerate(stations):
left = max(0, i - r)
right = min(n, i + r + 1)
diff[left] += val
diff[right] -= val
# 判断猜的数字是否合法
def f(c):
# 临时电站的差分数组
td = defaultdict(int)
# 本次猜测剩余可加电站数
tk = k
# 当前位置覆盖的电站数
cnt = 0
for i in range(n):
# i 处的电站数
cnt += diff[i] + td[i]
if cnt < c:
# 将该位置电站数补充到 c
tk -= c - cnt
if tk < 0:
# 剩余可加电站不足
return False
# 补充的电站放在 min(n - 1, i * 2 * r) 处
td[min(n, i + 2 * r + 1)] -= c - cnt
# 更新该位置的电站数
cnt = c
return True
#预估上下界
a, b = min(stations), sum(stations) + k
# 维护左边界合法
while a + 1 < b:
c = a + (b - a) // 2
if f(c):
a = c
else:
b = c - 1
if f(b):
return b
return a
复杂度分析
- 时间复杂度:$O(n \log D)$。每次猜测的时间复杂度为 $O(n)$,需要进行$D = sum(stations) + k - min(stations)$次猜测,总复杂度为 $O(n \log D)$.
- 空间复杂度:$O(n)$.
补充:差分数组
给定边界 $S \geq 0$,数组 $arr$,其中 $arr[i] = [a_{i}, b_{i}],\ (0 \leq a_{i} \leq b_{i} \leq S)$,表示在 $[a_{i}, b_{i}]$ 内每个整数位置都放一个小球,返回每个坐标下的小球数量列表。
若采用暴力方法,时间复杂度为 $O(nS)\ (n = len(arr))$。
def function(arr: list[list[int]], S: int) -> list[int]:
ans = [0] * (S + 1)
for a, b in arr:
for i in range(a, b + 1):
ans[i] += 1
return ans
实际上,我们只要记录每个坐标和前一个坐标的差值,即可在 $O(S)$ 的时间内计算出每个位置最后的小球数。
创建数组 $diff$,其中 $diff[i]$ 表示 $i$ 位置和 $i - 1$位置的差值,则 $ans[i] = ans[i - 1] + diff[i]$,其中$ans[0] = 0 + diff[0]$.
那么如何建立差分数组 $diff$ 呢?对于 $arr[i] = [a_{i}, b_{i}]$,表面含义是在 $[a_{i}, b_{i}]$ 内每个整数位置都放一个小球,我们可以从另一个角度理解:
- 位置 $a_{i}$ 相对于位置 $a_{i} - 1$来说,多增加了一个球,所以差值 $diff[a_{i}] += 1$
- 位置 $b_{i} + 1$ 相对于位置 $b_{i}$来说,少增加了一个球,所以 $diff[b_{i} + 1] -= 1$
- 对于 $[a_{i} + 1, b_{i}]$ 内的位置来说,和前一个位置一样,都增加了一个小球,所以差值没变,不需要修改差分数组 $diff$
调整差分数组的时间复杂度为$O(n)\ (n = len(arr))$,根据差分数组求每个位置小球数的时间复杂度为 $O(S)$,则总时间复杂度为 $O(n) + O(S) = O(\min(n, S))$.
def function(arr: list[list[int]], S: int) -> list[int]:
# 建立差分数组
diff = defaultdict(int)
# 调整差分数组
for a, b in arr:
diff[a] += 1
diff[b] -= 1
# 根据差分数组求各个位置的小球数
ans = [0] * (S + 1)
ans[i] = diff[0]
for i in range(1, S + 1):
ans[i] = ans[i - 1] + diff[i]
return ans
END
码字不易,点个赞再走呗!