5963. 反转两次的数字
思路:检查个位数
时间复杂度:
空间复杂度:
只要个位数是零,就会导致第一次翻转后出现前导零,进而导致第二次翻转后丢失前导零。反之,个位数非零则两次翻转后不会发生变化。特别的,需要单独考虑数字 。
class Solution {
public:
bool isSameAfterReversals(int num) {
if (num != 0 && num%10 == 0) {
return false;
}
return true;
}
};
5964. 执行所有后缀指令
思路:暴力枚举,模拟。
时间复杂度:
空间复杂度:。不包含存储答案的空间开销。
枚举起始位置 ,然后机器人从初始位置出发,依次执行 条命令。在执行过程中,检测机器人的位置是否合法即可。
class Solution {
public:
int walk(int n, int x, int y, const char *cmd) {
int i = 0;
for (i = 0; cmd[i] != '\0'; i++) {
int dx = 0, dy = 0;
// 计算当前指令的位移方向
switch (cmd[i]) {
case 'L': dy = -1; break;
case 'R': dy = 1; break;
case 'U': dx = -1; break;
case 'D': dx = 1; break;
}
// 计算下一个位置
int nx = x + dx, ny = y + dy;
// 检查下一个位置是否合法
if (0 <= nx && nx < n && 0 <= ny && ny < n) {
x = nx, y = ny;
} else {
return i;
}
}
return i;
}
vector<int> executeInstructions(int n, vector<int>& startPos, string s) {
// anw 用于存储答案
vector<int> anw;
for (int i = 0; i < s.size(); i++) {
// 枚举执行命令的起始位置
anw.push_back(walk(n, startPos[0], startPos[1], s.c_str() + i));
}
return anw;
}
};
5965. 相同元素的间隔之和
思路:前缀和
时间复杂度:
空间复杂度:
考虑位置 ,如果我们知道
- 在区间 中,数字 出现的次数 及其位置之和 。
- 在区间 中,数字 出现的次数 及其位置之和 。
则位置 的间隔之和可表示为:
因此,我们我们只需
- 正向遍历一次 ,统计出所有的 和 ,并计算 。
- 逆序遍历一次 ,统计出所有的 和 ,并计算
详见注释~
class Solution {
public:
vector<long long> getDistances(vector<int>& arr) {
// mark.first 表示arr中出现的数字
// mark.second.first 表示位置之和
// mark.second.second 表示出现次数
unordered_map<int, pair<int64_t, int64_t>> mark;
// anw 用于存储答案
vector<long long> anw(arr.size());
// 开始正序遍历
for (int i = 0; i < arr.size(); i++) {
auto &data = mark[arr[i]];
// 从 mark 中取出 sum_{i,0} 和 cnt_{i,0},更新 anw[i]
anw[i] += data.second * 1L * i - data.first;
// 更新 sum_{i,0} 和 cnt_{i,0}
data.second ++;
data.first += i;
}
// 重置 mark,以便在逆序遍历中使用
mark.clear();
// 开始逆序遍历
for (int i = arr.size()-1; i >= 0; --i) {
auto &data = mark[arr[i]];
// 从 mark 中取出 sum_{i,1} 和 cnt_{i,1},更新 anw[i]
anw[i] += data.first - data.second * 1L * i;
// 更新 sum_{i,1} 和 cnt_{i,1}
data.second ++;
data.first += i;
}
return anw;
}
};
5966. 还原原数组
思路:枚举
时间复杂度:
空间复杂度:
假设已知 ,则可按下述思路构造答案 。
中的最小值一定在 中,因此可从 中删除最小值 以及 ,并将 放入 中。重复这个过程,直到 变为空。借助哈希表,这个过程的时间复杂度可以做到 。
但现在我们不知道 ,因此需先找到所有可能的 。先将 排序,然后判断 是否大于零且能被 2 整除。如果可以,则 即是一个可能的 。
因为 的候选值不会超过 个,所以我们可枚举所有的候选值,然后尝试构造。整体的时间复杂度为 。
详见注释~
class Solution {
public:
vector<int> recoverArray(vector<int>& nums) {
// 寻找 k 的候选值,并存储到 cand 中。
sort(nums.begin(), nums.end());
unordered_set<int> cand;
for (int i = 1; i < nums.size(); i++) {
if (((nums[i] - nums[0])&1) == 0 && nums[i] != nums[0]) {
cand.insert((nums[i]-nums[0])/2);
}
}
// anw 用于存储答案
vector<int> anw;
// 构造哈希表,以便实现 O(n) 构造过程。
unordered_multiset<int> mark1;
for (auto num : nums) {
mark1.insert(num);
}
// 枚举 k
for (auto k : cand) {
// 初始化 anw 和 mark,用于一次构造过程
unordered_multiset<int> mark = mark1;
anw.resize(0);
anw.reserve(nums.size()/2);
// 从小到大枚举 nums
for (int i = 0; i < nums.size(); i++) {
int num = nums[i];
auto fit = mark.find(num);
// 如果 num 不在 mark 中,说明已经被删除了,继续下一个。
if (fit == mark.end()) { continue; }
// num 在 mark 中,则 num+2k 必须在 mark 中。即 num 属于 lower,num+2k 属于 higher
auto sit = mark.find(num + 2*k);
if (sit == mark.end()) {
break;
}
// 删除 num 和 num+2k,并将 num+k 放入 anw 中。
anw.push_back(num + k);
mark.erase(fit);
mark.erase(sit);
}
// 构造成功,返回答案。否则继续处理下一个候选值
if (anw.size() == nums.size()/2) {
return anw;
}
}
// 题目保证了一定有答案,因此不会执行到这。加这个只是为了消除编译报警。
return vector<int>{};
}
};