LeetCode 第 291 场周赛题解及思路
6047. 移除指定数字得到的最大结果
给你一个表示某个正整数的字符串
number
和一个字符digit
。
从number
中 恰好 移除 一个 等于digit
的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足digit
在number
中出现至少一次。
一看数据量,字符串长度不到 100 呀,那没事了,我就把所有移除相应字符后的所有子字符串全部找出来呗,然后从大到小排个序,最大的那个就是结果呀。
需要注意的是,字符串排序的默认方式就是按照 字典序,所以和大整数的大小是对应的,因此没有必要把字符串转化为整数再排序哈。
vector<string> v;
int n = number.size();
for (int i = 0; i < n; i++)
if (number[i] == digit)
v.push_back(number.substr(0, i) + number.substr(i + 1));
sort(v.begin(), v.end(), greater<string>());
return v[0];
完整代码见 GitHub。
6048. 必须拿起的最小连续卡牌数
给你一个整数数组
cards
,其中cards[i]
表示第i
张卡牌的 值 。如果两张卡牌的值相同,则认为这一对卡牌 匹配 。
返回你必须拿起的最小连续卡牌数,以使在拿起的卡牌中有一对匹配的卡牌。如果无法得到一对匹配的卡牌,返回-1
。
做个合格的翻译是一名程序员成长的必经之路,简单概括题目意思就是,找到两个相同数字的最短间距。
所以我们可以遍历数组,对于当前字符,找到 之前的、最近的相同数字,求出这俩数字的位置绝对差值并更新结果即可。
for (int i = 0; i < cards.size(); i++) {
int j = i - 1;
for (; j >= 0; j--)
if (cards[i] == cards[j])
break;
if (j >= 0)
ans = min(ans, i - j + 1);
}
但是由于数据量达到了 1 0 5 10^5 105,所以上述方式会超时,因此在找相同数字的时候不可以采用遍历的方式。所以我们想到用 哈希表 来记录某种数字最近的下标,这样就可以在 O ( 1 ) O(1) O(1) 时间内找到相同数字,当然,遍历过程中要更新维护这个哈希表。
unordered_map<int, int> indexs;
int ans = 0x7fffffff;
for (int i = 0; i < cards.size(); i++) {
if (indexs.count(cards[i])) // 判断该字符是否曾经出现过
ans = min(ans, i - indexs[cards[i]] + 1;
indexs[cards[i]] = i;
};
最后别忘记,如果数组中所有数字都不相同的话,就找不到一对匹配的卡牌,需要返回 -1
。
return ans == 0x7fffffff ? -1 : ans;
完整代码见 GitHub。
6049. 含最多 K 个可整除元素的子数组
给你一个整数数组
nums
和两个整数k
和p
,找出并返回满足要求的不同的子数组数,要求子数组中最多k
个可被p
整除的元素。
如果满足下述条件之一,则认为数组nums1
和nums2
是 不同 数组:1). 两数组长度 不同 ,2). 或者存在 至少 一个下标i
满足nums1[i] != nums2[i]
。
子数组 定义为:数组中的连续元素组成的一个 非空 序列。
看到题目我第一眼想到的竟然是 动态规划,即 dp[i][j]
代表以第 i
个元素为最后一个元素且被 p
整除的元素个数为 j
个的子数组集合,然后就可以迭代求解。
但是这么做有个大问题。虽然上面理论上复杂度也是
O
(
n
p
)
O(np)
O(np),但是 C++
中集合插入太耗时了,导致我竟然超时了。
于是我认真看了一眼数据量,发现我多半是疯魔了,直接把每个子数组找出来不就好了?这样时间复杂度也就是 O ( n 2 ) O(n^2) O(n2),但是无论是从代码复杂度还是集合插入操作来说,都简单多的多了,正可谓大道至简。
int n = nums.size();
set<vector<int>> ans;
for (int i = 0; i < n; i++) {
vector<int> v;
int cnt = 0; // 记录能够除余 p 的元素个数
for (int j = i; j < n; j++) {
cnt += !(nums[j] % p);
// 如果已经超出要求,那么之后的 j 肯定也不满足要求,直接退出即可。
if (cnt > k) break;
// 将当前元素压入子数组,再将子数组插入结果集合中
v.push_back(nums[j]);
ans.insert(v);
};
};
return ans.size();
完整代码见 GitHub。
6050. 字符串的总引力
字符串的 引力 定义为:字符串中 不同 字符的数量。给你一个字符串
s
,返回 其所有子字符串的总引力 。
子字符串 定义为:字符串中的一个连续字符序列。
题目简洁明了,一看通过人数蹭蹭往上涨,数据量也有 1 0 5 10^5 105 不小,按照这个子字符串定义,这个字符串的所有子字符串应该有 1 0 10 10^{10} 1010 个,那就算每个子字符串我都能以 O ( 1 ) O(1) O(1) 的时间复杂度求出它的引力,也必然超时啊。
所以肯定是要整体求解,不能单独考虑某个子字符串,而是要 一次考虑一组子字符串。
对于字符串中的每个字符 s[i]
,我们可以考虑 s[i]
第一次 出现在子字符串中的情况,即子字符串中在 s[i]
的左侧没有和 s[i]
一样的字符。
那么有多少种情况呢?我们可以想象以 i
为中心向左向右分别延伸,向左延伸到和 s[i]
相同字符的位置处 l
就得停止,而向右则可以延伸到数组尽头。即左侧有 i - l
种情况,右侧有 n - i
种情况,排列组合一下,就是 (i - l) * (n - i)
种情况。
具体实现的时候,可以假设所有种类的字符最近的出现都是在数组下标为 -1
的时候,还要注意数据范围比较大要用长整型。
long long n = s.size(), ans = 0;
vector<long long> indexs(26, -1);
for (long long i = 0; i < n; i++) {
long long l = (indexs[s[i] - 'a']);
ans += (i - l) * (n - i);
indexs[s[i] - 'a'] = i;
};
return ans;
完整代码见 GitHub。
俺已经开启了快乐 充实的五一假期啦,有好多好多作业要写呀,当然最重要的还是要好好过和女朋友的一周年纪念日啦 ~ 开心子 ~
好啦,以上就是力扣第 291 场周赛的全部思路啦。最后,欢迎关注我的 GitHub 账号。