AI刷题记录(二) | 豆包MarsCode AI刷题
绿洲之旅:最少补给次数探索
问题描述
小U正在准备穿越一片广阔的沙漠。沙漠里有多个绿洲,每个绿洲设有补给站。所有补给站的收费相同,但提供的水量不同。从起点到终点共有 (D) 公里,小U需要规划在哪些补给站停留,以保证整个旅途中水的供应。
起点到终点的距离为 (D) 公里,小U初始携带 (W) 升水,每行走 1 公里消耗 1 升水。小U希望通过最少的补给次数安全到达终点。每个补给站的位置由 position[i] 表示,距离起点的公里数,supply[i] 表示该站可以提供的水量,单位为升。
请你帮助小U计算,要安全到达终点至少需要补给几次,或者判断是否根本无法到达终点,此时输出-1。
思路
设 为第 个补给站距离起点的距离, 为第 个补给站能补给的水容量,将起点和终点视作特殊补给站则有, 。
背包动态规划,定义状态方程 表示到达第 个补给站时,水还剩 升所需的最小补给次数,则可以得出状态转移方程。
代码
def solution(d, w, position, supply):
p = [0] + position + [d]
s = [0] + supply + [0]
n = len(p)
m = sum(s) + w
dp = [[int(1e9)] * (m+1) for _ in range(n)]
dp[0][w] = 0
for i in range(1, n):
for j in range(m+1):
if j + p[i] - p[i - 1] <= m:
dp[i][j] = min(dp[i][j], dp[i - 1][j + p[i] - p[i - 1]])
if 0 <= j + p[i] - p[i - 1] - s[i - 1] <= m:
dp[i][j] = min(dp[i][j], dp[i - 1][j + p[i] - p[i - 1] - s[i - 1]] + 1)
ans = min(dp[-1][:])
return ans if ans < int(1e9) else -1
子数组和的最大值问题
问题描述
小U手上有一个整数数组,他想知道如果从数组中删除任意一个元素后,能得到的长度为 k 的子数组和的最大值。你能帮小U计算出这个结果吗?
如果数组恰好为 k 个元素,那么不进行删除操作。
思路
- 不考虑删除操作:设置长度为 滑动窗口,窗口元素和最大值即为子数组和的最大值。
- 考虑删除操作:等于滑动窗口的长度变成 ,但需要删除最小元素值,这个可以使用优先队列来维护。
对于Python实现,需要注意Python的优先队列获取元素的put()方法会同时弹出元素,但子数组中最小值必须在滑出窗口后再移除,因此需要每次取完最小值后都需要将该值重新压入优先队列中。
代码
from queue import PriorityQueue
def solution(n, k, nums):
nums.append(int(-1e9))
n+=1
q = PriorityQueue()
s=0
ans=int(-1e9)
sz=0
k+=1
for i in range(k-1):
q.put((nums[i], i))
sz+=1
s+=nums[i]
for i in range(k-1, n):
s=s+nums[i]
q.put((nums[i],i))
if i-k>=0:s-=nums[i-k]
while True:
y, j = q.get()
sz-=1
if j+k-1>=i:
q.put((y,j))
sz+=1
break
y, j = q.get()
ans=max(ans,s-y)
q.put((y,j))
sz+=1
return ans
字符串解压缩
问题描述
小U拿到了一个通过特殊方式压缩的字符串,其中每个字母后面可能跟着一个数字,这个数字表示该字母在解压后的字符串中需要重复的次数。如果一个字母后面没有跟随数字,那么该字母在解压后的字符串中只出现一次。请帮助小U解压这个字符串并输出最终的解压结果。
思路
Python友好题,从s中取出数字并对前一个字母做复制即可。
代码
def solution(s: str) -> str:
n=len(s)
i = 0
ret=[]
while i<n:
if s[i].isdigit():
j=i
while j<n and s[j].isdigit():
j+=1
x=int(s[i:j])
ret[-1]=ret[-1]*x
i=j-1
else:
ret.append(s[i])
i+=1
return ''.join(ret)
二进制之和
问题描述
小U和小R喜欢探索二进制数字的奥秘。他们想找到一个方法,将两个二进制字符串相加并以十进制的形式呈现。这个过程需要注意的是,他们的二进制串可能非常长,所以常规的方法可能无法处理大数。小U和小R希望你帮助他们设计一个算法,该算法能在保证时间复杂度不超过O(n^2)的前提下,返回两个二进制字符串的十进制求和结果。
思路
此题主要是考察高精度运算和高精度进制转换。
不过Python可以直接
x = int(binary1, 2)
y = int(binary2, 2)
return str(x+y)
代码
auto mul(std::vector<int> pow, int x) -> std::vector<int> {
std::vector<int> buf(pow.size() + 1, 0);
int p = 0;
for (int i = 0; i < pow.size(); i++) {
buf[i] = (p + pow[i] * x) % 10;
p = (p + pow[i] * x) / 10;
}
if (p) buf[buf.size() - 1] = p;
else buf.pop_back();
return buf;
}
auto add(std::vector<int> a, std::vector<int> b) -> std::vector<int> {
std::vector<int> buf(std::max(a.size(), b.size()) + 1, 0);
int p = 0;
for (int i = 0; i < std::max(a.size(), b.size()); i++) {
int x = 0, y = 0;
if (i < a.size()) {
x = a[i];
}
if (i < b.size()) {
y = b[i];
}
buf[i] = (p + x + y) % 10;
p = (p + x + y) / 10;
}
if (p) buf[buf.size() - 1] = p;
else buf.pop_back();
return buf;
}
std::string solution(std::string binary1, std::string binary2) {
std::reverse(binary1.begin(), binary1.end());
std::reverse(binary2.begin(), binary2.end());
int n = std::max(binary1.length(), binary2.length());
std::vector<int> res;
int p = 0;
for (int i = 0; i < n; i++) {
int a = 0, b = 0;
if (i < binary1.length()) {
a = binary1[i] - '0';
}
if (i < binary2.length()) {
b = binary2[i] - '0';
}
res.emplace_back((p + a + b) % 2);
p = (p + a + b) / 2;
}
if (p) res.emplace_back(p);
std::vector<int> ans(1, 0), pow(1, 1);
for (int i = 0; i < res.size(); i++) {
if (res[i]) {
ans = add(ans, pow);
}
pow = mul(pow, 2);
}
std::string ret;
for (int i = ans.size() - 1; i >= 0; i--) {
ret += ans[i] + '0';
}
return ret;
}