LeetCode周赛276场,Amazon赞助,你能做出几题?

作者 | 梁唐

出品 | 公众号:Coder梁(ID:Coder_LT)

大家好,我是梁唐。

昨天参加了LeetCode第276场周赛,这场周赛的美国区是Amazon赞助的。

不知道是不是给钱比较多的缘故,这次的题目质量很高,非常值得一做,我们一道一道来看题解吧。

字符串拆分

字符串 s 可以按下述步骤划分为若干长度为 k 的组:

  • 第一组由字符串中的前 k 个字符组成,第二组由接下来的 k 个字符串组成,依此类推。每个字符都能够成为 某一个 组的一部分。
  • 对于最后一组,如果字符串剩下的字符 不足 k 个,需使用字符 fill 来补全这一组字符。

注意,在去除最后一个组的填充字符 fill(如果存在的话)并按顺序连接所有的组后,所得到的字符串应该是 s 。

给你一个字符串 s ,以及每组的长度 k 和一个用于填充的字符 fill ,按上述步骤处理之后,返回一个字符串数组,该数组表示 s 分组后 每个组的组成情况 。

解法

模拟题,按照题目要求分别取出s串中长度为k的子串。

最后不够拆分的部分需要特殊处理,通过下标是否超过s范围来判断即可。

class Solution {
public:
    vector<string> divideString(string s, int k, char fill) {
        vector<string> ret;
        int n = s.length();
        for (int i = 0; i < n; i += k) {
            if (i+k < n) 
                // 如果还能拆分,则取出s[i, i+k]子串
                ret.push_back(s.substr(i, k));
            else {
                // 不能拆分
                string cur = "";
                // 下标超过范围则选fill,否则选s[j]
                for (int j = i; j < i+k; j++) {
                    if (j < n) cur.push_back(s[j]);
                    else cur.push_back(fill);
                }
                ret.push_back(cur);
            }
        }
        
        return ret;
    }
};

得到目标值的最小行动步数

你正在玩一个整数游戏。从整数 1 开始,期望得到整数 target 。

在一次行动中,你可以做下述两种操作之一:

  • 递增,将当前整数的值加 1(即, x = x + 1)。
  • 加倍,使当前整数的值翻倍(即,x = 2 * x)。

在整个游戏过程中,你可以使用 递增 操作 任意 次数。但是只能使用 加倍 操作 至多 maxDoubles 次。

给你两个整数 target 和 maxDoubles ,返回从 1 开始得到 target 需要的最少行动次数。

解法

这里要注意一下target的范围是1e9,显然,当target很大,而maxDoubles很小时,我们需要采取的步骤数很大。比如记得情况当maxDoubles为0时,答案的大小同样是1e9。

因此选择搜索的方式是不行的,一定会超时。

深入思考可以想到,可以采取的决策只有两种,加一或者是翻倍。游戏中我们当前的数永远大于等于1,显然翻倍带来的提升一定是大于加一的。而翻倍之前的值越大翻倍带来的收益越大,所以越晚翻倍越划算,需要的步骤越少。可以考虑贪心,从target往1进行倒推。

当target为奇数时,肯定不能通过翻倍得到,只能通过加一得到,所以之前一位操作一定是加一。如果为偶数,当翻倍次数没有超过maxDoubles时,一定是使用翻倍得到最优,否则只能使用加一。

class Solution {
public:
    int minMoves(int target, int maxDoubles) {
        int ret = 0;
        while (target > 1) {
            // 如果为奇数,之前一位操作一定是+1
            if (target % 2) {
                ret++;
                target--;
                continue;
            }
            // 如果为偶数,且翻倍操作还没用完,则之前一位操作为翻倍
            if (maxDoubles > 0) {
                maxDoubles--;
                target /= 2;
                ret++;
            // 如果用完了所有翻倍次数,只能通过+1得到
            }else {
                ret += (target-1);
                break;
            }
        }
        return ret;
    }
};

解决智力问题

给你一个下标从 0 开始的二维整数数组 questions ,其中 questions[i] = [pointsi, brainpoweri] 。

这个数组表示一场考试里的一系列题目,你需要 按顺序 (也就是从问题 0 开始依次解决),针对每个问题选择 解决 或者 跳过 操作。解决问题 i 将让你 获得 pointsi 的分数,但是你将 无法 解决接下来的 brainpoweri 个问题(即只能跳过接下来的 brainpoweri 个问题)。如果你跳过问题 i ,你可以对下一个问题决定使用哪种操作。

  • 比方说,给你 questions = [[3, 2], [4, 3], [4, 4], [2, 5]] :
    • 如果问题 0 被解决了, 那么你可以获得 3 分,但你不能解决问题 1 和 2 。
    • 如果你跳过问题 0 ,且解决问题 1 ,你将获得 4 分但是不能解决问题 2 和 3 。请你返回这场考试里你能获得的 最高 分数。

解法

这是一道典型的动态规划问题,我们使用数组arr存储中间状态的最优解。arr[i]表示对于在回答第i题之前,能够获得的最大分数。

那么在第i题回答之后,所能得到的分数为arr[i] + questions[i][0],我们把它记录为变量c。由于第i题如果回答,会需要连续跳过questions[i][1]题。我们可以把连续跳过若干题看成是一种状态转移,可以从状态i转移到所有大于i+questions[i][1]的状态中。

由于这样的转移数很多,如果我们一一穷举会超时,我们可以采用滚动维护的方法,只更新i+questions[i][1]+1的状态,在每个状态开始执行之前,传递一下arr[i],即执行arr[i] = max(arr[i-1], arr[i])

class Solution {
public:
    long long arr[2000050];
    
    long long mostPoints(vector<vector<int>>& questions) {
        long long ret = 0;
        int n = questions.size();
        
        for (int i = 0; i < n; i++) {
            // 滚动维护状态i的最大值
            if (i > 0) arr[i] = max(arr[i], arr[i-1]);
            // 当前问题回答之后能够达到的收益
            long long c = arr[i] + questions[i][0];
            ret = max(ret, c);
            int next = i + questions[i][1] + 1;
            // 更新状态next,对于next之后的位置可以通过arr[i] = max(arr[i], arr[i-1]);维护
            if (next < n) arr[next] = max(arr[next], c);
        }
        
        return ret;
    }
};

同时运行N台电脑的时间

你有 n 台电脑。给你整数 n 和一个下标从 0 开始的整数数组 batteries ,其中第 i 个电池可以让一台电脑 运行 batteries[i] 分钟。你想使用这些电池让 全部 n 台电脑 同时 运行。

一开始,你可以给每台电脑连接 至多一个电池 。然后在任意整数时刻,你都可以将一台电脑与它的电池断开连接,并连接另一个电池,你可以进行这个操作 任意次 。新连接的电池可以是一个全新的电池,也可以是别的电脑用过的电池。断开连接和连接新的电池不会花费任何时间。

注意,你不能给电池充电。

请你返回你可以让 n 台电脑同时运行的 最长 分钟数。

解法

同样通过数据范围, 我们可以判断出一定不能使用搜索或其他复杂度更高的解法。

首先,通过仔细分析题意,我们可以得到几个性质,我们可以把电池更换的操作看成是充电。比如A电池运行1分钟之后,换上B电池,可以等价看成是A电池给B电池充上了一分钟电。其次对于每个电池来说,最多只能同时在一个位置使用,要么给某台电脑供电,要么给其他某节电池充电,不能同时使用在两个地方。

我们不难可以想到,可以将电池按照电量倒排之后分成两组。电量最大的N个电池用来给电脑供电,剩余的M(M=batteries.size()-N)个电池用来给这N个电池充电。我们可以把充电看成是电量累加,要求的就是在累加之后,N当中的最小值的最大取值。

经过这么一番转换之后,很容易想到,我们要做的就是用M个电池给N个电池充电,尽量让N个电池的电量平均。由于每个电池的电量都是可以拆分的,比如可以先给A充一分钟,再给B充一分钟。所以我们可以将它们的电量合并统筹分配。

我们先从电量最少的电池开始充电,将它充到和倒数第二的电池一样,再同时给这两个电池充电,充到和倒数第三的电池一样。依次循环往复,直到所有电池电量均等,或者能充的电量用完为止。最后如果还有剩余,再分配到所有电池上。

class Solution {
public:
    long long maxRunTime(int n, vector<int>& batteries) {
        int k = batteries.size();
        if (k < n) return 0;
        // 按电池电量倒叙排列
        sort(batteries.begin(), batteries.end(), greater<int>());
        
        long long ret = batteries[n-1];
        long long left = 0;
        // 求出充电组的电量总和
        for (int i = n; i < k; i++) left += batteries[i];
        
        int s = n-1;
        // 从电量最低的电池开始充电
        while (left > 0 && s > 0) {
            // 充电的量为要充电的电池数*和前一位的电量差距
            long long req = (n-s) * (batteries[s-1] - batteries[s]);
            if (left >= req) {
                left -= req;
                ret += batteries[s-1] - batteries[s];
            }else {
                ret += left / (n-s);
                left = 0;
                break;
            }
            s--;
        }
        // 如果所有电池电量相等之后还有剩余,就平均分配
        if (left > 0) ret += left / n;
        return ret;
    }
};

到这里,关于这一场的四道题就算是讲完了。

这一场的题目不算很难,也没用到什么高深的算法,主要考察的还是思维的活跃以及对问题的分析。我个人还是很喜欢这套题的,强力推荐给大家,如果有空的话,不妨都做一做。

原文地址:https://cloud.tencent.com/developer/article/2117512

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340