AI刷题记录(二) | 豆包MarsCode AI刷题

116 阅读4分钟

AI刷题记录(二) | 豆包MarsCode AI刷题

绿洲之旅:最少补给次数探索

问题描述

小U正在准备穿越一片广阔的沙漠。沙漠里有多个绿洲,每个绿洲设有补给站。所有补给站的收费相同,但提供的水量不同。从起点到终点共有 (D) 公里,小U需要规划在哪些补给站停留,以保证整个旅途中水的供应。

起点到终点的距离为 (D) 公里,小U初始携带 (W) 升水,每行走 1 公里消耗 1 升水。小U希望通过最少的补给次数安全到达终点。每个补给站的位置由 position[i] 表示,距离起点的公里数,supply[i] 表示该站可以提供的水量,单位为升。

请你帮助小U计算,要安全到达终点至少需要补给几次,或者判断是否根本无法到达终点,此时输出-1。

思路

pip_{i} 为第 ii 个补给站距离起点的距离, sis_i 为第 ii 个补给站能补给的水容量,将起点和终点视作特殊补给站则有, p0=0,pn1=d,s0=0,sn1=0p_0=0,p_{n-1}=d,s_0=0,s_{n-1}=0

背包动态规划,定义状态方程 f(i,j)f(i, j) 表示到达第 ii 个补给站时,水还剩 jj 升所需的最小补给次数,则可以得出状态转移方程。

f(i,j)={f(i1,j+pipi1不补给f(i1,j+pipi1+si1补给f(i,j)= \begin{cases} f(i-1, j+p_i-p_{i-1} \quad \text{不补给} \\ f(i-1, j+p_i-p_{i-1}+s_{i-1} \quad \text{补给} \\ \end{cases}

代码

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 个元素,那么不进行删除操作。

思路

  • 不考虑删除操作:设置长度为 kk 滑动窗口,窗口元素和最大值即为子数组和的最大值。
  • 考虑删除操作:等于滑动窗口的长度变成 k+1k+1 ,但需要删除最小元素值,这个可以使用优先队列来维护。

对于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;
}