力扣周赛(节选)2022-04-30
6404. 将数组清空
关键词:树状数组、找规律
题目来源:6404. 将数组清空 – 力扣(Leetcode)——力扣第 103 场双周赛第4题
题目描述
T树状数组
T找规律
给你一个包含若干 互不相同 整数的数组 nums
,你需要执行以下操作 直到数组为空 :
- 如果数组中第一个元素是当前数组中的 最小值 ,则删除它。
- 否则,将第一个元素移动到数组的 末尾 。
请你返回需要多少个操作使 nums
为空。
问题分析
问题等价于:设一指针p初始指向nums[0],指针p把不断从左往右扫描(扫描到末尾则从头开始扫描),每扫描到当前数组的最小值,就将其标记为“删除”,然后继续扫描,直到数组所有元素均被标记为“删除”,求指针总共需要移动多少步,标记为删除的位置在移动时直接忽略。
设上一个最小值的位置为pre,也即上次标记为“删除”的位置为pre,当前最小值的位置为i。
先考虑i≥pre的情况,则从pre移动到i共需i-pre步。又因为
- 这个i-pr步中,有些位置已经被删除,移动时直接被忽略,不记录到实际步数中;
- 将一个位置标记为“删除”,指针p便会顺移到下一个未被删除的位置,所以指针并不是从pre开始移动的。
设实际需要移动k步,则k=(i-pre)-[pre+1..i]中被删除的位置-1。
再考虑i
以上只考虑到移动的次数,题目还需加上删除操作的次数,故答案最后需要+n。
经过分析发现,需要维护区间被删除的位置的个数,因而想到树状数组(或者线段树)。
代码实现
// 树状数组模板 const int N = 1e5 + 5; int tr[N], n; int lowbit(int x) { return x & -x; } void add(int x) { for (int i = x; i &nums) { n = nums.size(); int idx[n]; iota(idx, idx + n, 1); // 从1开始 sort(idx, idx + n, [&](int &i, int &j) { return nums[i - 1] = pre) { // 从pre移动到i,并且跳过已删除的数 res += (i - pre) - (query(i) - query(pre)) - 1; } else { // 从pre移动到n,从1移动到i,并且跳过已删除的数 res += (n - pre + i) - (query(n) - query(pre)) - (query(i)) - 1; } add(i), pre = i; } return res; }
时间复杂度:O(nlog(n))
空间复杂度:O(n)
6343. 前往目标的最小代价
关键词:单源最短路、深度优先
题目来源:6343. 前往目标的最小代价 - 力扣(Leetcode)——力扣第 343 场周赛第3题
题目描述
T单源最短路 T深度优先
给你一个数组
start
,其中start = [startX, startY]
表示你的初始位置位于二维空间上的(startX, startY)
。另给你一个数组target
,其中target = [targetX, targetY]
表示你的目标位置(targetX, targetY)
。从位置
(x1, y1)
到空间中任一其他位置(x2, y2)
的代价是|x2 - x1| + |y2 - y1|
。给你一个二维数组
specialRoads
,表示空间中存在的一些特殊路径。其中specialRoads[i] = [x1i, y1i, x2i, y2i, costi]
表示第i
条特殊路径可以从(x1i, y1i)
到(x2i, y2i)
,但成本等于costi
。你可以使用每条特殊路径任意次数。返回从
(startX, startY)
到(targetX, targetY)
所需的最小代价。输入:start = [1,1], target = [4,5], specialRoads = [[1,2,3,3,2],[3,4,4,5,1]] 输出:5
输入:start = [3,2], target = [5,7], specialRoads = [[3,2,3,4,4],[3,3,5,5,5],[3,4,5,6,6]] 输出:7
数据范围 start.length == target.length == 2 1
单源最短路
可能经过的点只有源点、终点和特殊路径上的点,故本题可转化为简单的单源最短路问题,由于是稠密图,故采用朴素Dijkstra算法即可。
int minimumCost(vector
&start, vector &target, vector > &specialRoads) { using ll = long long; ll t = (ll) target[0] dis = {{s, 0}, {t, INT_MAX}}; // 标记一个点是否被访问 unordered_set vis; while (true) { // 找到距离源点最近的点 ll p = -1; for (auto &d: dis) if (vis.find(d.first) == vis.end() && (p > 32, ty = p & UINT32_MAX; dis[t] = min(dis[p] + target[0] - tx + target[1] - ty, dis[t]); for (auto &r: specialRoads) { // 源点s到(r[2],r[3])的距离 // 要从p直接到(r[2],r[3]),要么从p经过特殊路径到(r[2],r[3]) int x = r[2], y = r[3]; int d = dis[p] + min( abs(x - tx) + abs(y - ty), abs(r[0] - tx) + abs(r[1] - ty) + r[4] ); // 更新距离 ll tp = (ll) x 时间复杂度:O(n^2)。其中,n指的是specialRoads的长度
空间复杂度:O(n)
深度优先
由于数据规模并不是很大,
1 ,故采用深搜来枚举每种可能也可以通过大部分数据(1038 / 1040)。
进行深搜前可以将特殊路径按其起点与源点的距离排序,从而加快最小值的获取。
int minimumCost(vector
&start, vector &target, vector > &specialRoads) { auto &v = specialRoads; int len = v.size(); // 起点距离源点近的路径先枚举 sort(v.begin(), v.end(), [&](const auto &v1, const auto &v2) { return abs(v1[0] - start[0]) + abs(v1[1] - start[1]) dfs = [&](int x, int y, int cst) { if (cst >= minCost)return; minCost = min(cst + abs(target[0] - x) + abs(target[1] - y), minCost); for (int i = 0; i 6344. 字典序最小的美丽字符串
关键词:贪心
题目来源:6344. 字典序最小的美丽字符串 - 力扣(Leetcode)——力扣第 343 场周赛第4题
题目描述
T贪心
如果一个字符串满足以下条件,则称其为 美丽字符串 :
- 它由英语小写字母表的前
k
个字母组成。 - 它不包含任何长度为
2
或更长的回文子字符串。
给你一个长度为 n
的美丽字符串 s
和一个正整数 k
。
请你找出并返回一个长度为 n
的美丽字符串,该字符串还满足:在字典序大于 s
的所有美丽字符串中字典序最小。如果不存在这样的字符串,则返回一个空字符串。
对于长度相同的两个字符串 a
和 b
,如果字符串 a
在与字符串 b
不同的第一个位置上的字符字典序更大,则字符串 a
的字典序大于字符串 b
。
例如,"abcd"
的字典序比 "abcc"
更大,因为在不同的第一个位置(第四个字符)上 d
的字典序大于 c
。
输入:s = "abcz", k = 26
输出:"abda"
解释:字符串 "abda" 既是美丽字符串,又满足字典序大于 "abcz" 。
可以证明不存在字符串同时满足字典序大于 "abcz"、美丽字符串、字典序小于 "abda" 这三个条件。
输入:s = "dc", k = 4
输出:""
解释:可以证明,不存在既是美丽字符串,又字典序大于 "dc" 的字符串。
数据范围
1
问题分析
长度为m的回文串必然包含一个长度为m-2的字符串,又字符串s本就不含回文串,故只需要保证修改字符后不会出现长度为2或3的回文串,则字符串中就一定不含回文串。
题目要求字典序最小,故不断对字符串s进行+1,每次+1,检查是否出现回文串,若不出现回文串,说明找到符合要求的串。
代码实现
string smallestBeautifulString(string s, int k) {
int n = s.size(), i = n - 1;
k += 'a', s[i]++;
while (i 1 && s[i] == s[i - 2])s[i]++;
// 是否和后面字符构成回文串
else i++;
}
return s;
}
时间复杂度:O(n)
空间复杂度:O(1)
服务器托管,北京服务器托管,服务器租用 http://www.fwqtg.net