LeetCode 第 291 场周赛 题解及思路

本文介绍了LeetCode第291场周赛的四道题目,包括:移除指定数字得到的最大结果、找到必须拿起的最小连续卡牌数、含最多K个可整除元素的子数组以及字符串的总引力。针对每道题目,作者提供了解题思路和算法,涉及到字符串排序、哈希表、动态规划等技巧,并分享了完整代码链接。
摘要由CSDN通过智能技术生成

赛题传送门

6047. 移除指定数字得到的最大结果

赛题

给你一个表示某个正整数的字符串 number 和一个字符 digit
number恰好 移除 一个 等于 digit 的字符后,找出并返回按 十进制 表示 最大 的结果字符串。生成的测试用例满足 digitnumber 中出现至少一次。

一看数据量,字符串长度不到 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 和两个整数 kp ,找出并返回满足要求的不同的子数组数,要求子数组中最多 k 个可被 p 整除的元素。
如果满足下述条件之一,则认为数组 nums1nums2不同 数组: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 账号。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值