1 5746. 到目标元素的最小距离
class Solution {
public:
int getMinDistance(vector<int>& nums, int target, int start) {
int n = nums.size(), res = 0;
res = n;
for(int i = 0; i < n; i++)
if(nums[i] == target)
res = min(res, abs(i - start));
return res;
}
};
2 5747. 将字符串拆分为递减的连续值
思路:
- 只要第一个数确定了,后面所有数就确定了。
- 找出第1个数的所有可能情况,然后dfs即可。
typedef long long LL;
class Solution {
public:
string str;
LL get(int start, int len)//获得从start开始长度为len的字符串表示的数
{
LL res = 0;
for(int i = 0; i < len; i++)res = res * 10 + (str[start + i] - '0');
return res;
}
bool dfs(LL last, int start)
{
int n = str.size();
if(start == n)return true;
bool res = false;
for(int i = 1; start + i - 1 < n; i++)
{
LL num = get(start, i);
if(num == last - 1)res |= dfs(num, start + i);//可能新的num依旧等于last-1,所以不能在这里return(两次WA都是因为这个)
if(num > last - 1)return res;
}
return res;
}
bool splitString(string s) {
str = s;
int n = s.size();
for(int i = 1; i < n; i++)//枚举第1个数的所有可能情况
{
if(get(0, i) > 1e11)return false;//后面一个数不可能为前面一个数-1
if(dfs(get(0, i), i))
return true;
}
return false;
}
};
3 5749. 邻位交换的最小次数
参考:LeetCode官方题解
- 反思:当初做题太急躁,想一步求出第k个最小妙数。这里应该将问题分解,转化为求k次第1个最小妙数。
- 题解理解:
- 求k次当前num的下一个排列,得到第k个最小妙数numk。
- 设numk为1,2,3,…,n的一个升序序列,则num为1,2,3,…,n的一个排列,直接将numk和num这样映射可简化问题(只在在思路上映射,若num中含有重复元素,则所有同一重复元素在num和numk中相对位置保持不变)。则num中逆序对的数量为需要对num执行的相邻数字交换的最小次数(设为ans)。
- 贪心:同时遍历num和numk,只要num[i] != numk[i],则从i+1位置开始往后找到第1个值为numk[i]的数num[j]经过j - i次相邻交换放到位置i,ans += j - i。
- 第3点证明:因为当遍历到位置i时,经过之前的处理后num[1] ~ num[i-1]的所有元素均小于num[i],所以位置i到位置j-1(j为第3点中的j)的所有元素均大于num[j],所以每次相邻交换都能保证逆序对数量减1。遍历结束后最终逆序对数量为0,num变为numk。
class Solution {
public:
/*string nextPermutation(string nums) {
int k = nums.size() - 1;
while(k > 0 && nums[k - 1] >= nums[k])k--;
k--;
for(int i = nums.size() - 1; i > k; i--)
if(nums[i] > nums[k])
{
swap(nums[i], nums[k]);
break;
}
reverse(nums.begin() + k + 1, nums.end());
return nums;
}*/
int getMinSwaps(string num, int k) {
int n = num.size();
string num_k = num;
for(int i = 0; i < k; i++)next_permutation(num_k.begin(), num_k.end());//num_k = nextPermutation(num_k);
int res = 0;
for(int i = 0; i < n; i++)
if(num[i] != num_k[i])
for(int j = i + 1; j < n; j++)
if(num[j] == num_k[i])
{
for(int k = j; k > i; k--)
{
swap(num[k], num[k - 1]);
res++;
}
break;
}
return res;
}
};
4 5748. 包含每个查询的最小区间
参考:Leetcode官方题解
题解理解:
- 将区间左端点,右端点,查询点从左到右排序,值相同则按照左端点、查询点、右端点排序。
- 从左到右遍历,遇到左端点则将对应区间长度放入集合,遇到查询点则查询集合最小元素,遇到右端点则将对应长度从集合中剔除1个。
typedef pair<int, pair<int, int> >PIII;//<位置,<类型,区间长度/查询数组索引> >
class Solution {
public:
vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries) {
auto itv = intervals;
auto q = queries;
int n = itv.size(), m = q.size();
vector<PIII>a(2 * n + m);
for(int i = 0; i < n; i++)//左端点:type=-1,查询点:type=0,右端点:type=1,这样设方便第1点中的排序
{
int l = itv[i][0], r = itv[i][1];
int len = r - l + 1;
a.push_back({l, {-1, len}});
a.push_back({r, {1, len}});
}
for(int i = 0; i < m; i++)a.push_back({q[i], {0, i}});
sort(a.begin(), a.end());
multiset<int>segs;//有序可包含重复元素
vector<int>res(m, -1);
for(auto item : a)
{
int p = item.first, type = item.second.first, len = item.second.second;
if(type == -1)segs.insert(len);
else if(type == 0)
{
if(!segs.empty())res[len] = *segs.begin();//集合为空则赋值-1
}
else if(type == 1)segs.erase(segs.find(len));
}
return res;
}
};