到目标元素的最小距离
Leetcode 5746 到目标元素的最小距离题目链接
题目描述
给你一个整数数组
n
u
m
s
nums
nums (下标从 0 开始 计数)以及两个整数
t
a
r
g
e
t
target
target 和
s
t
a
r
t
start
start ,请你找出一个下标
i
i
i,满足
n
u
m
s
[
i
]
nums[i]
nums[i] ==
t
a
r
g
e
t
target
target 且
a
b
s
(
i
−
s
t
a
r
t
)
abs(i - start)
abs(i−start) 最小化 。注意:
a
b
s
(
x
)
abs(x)
abs(x) 表示
x
x
x 的绝对值。
返回
a
b
s
abs
abs(
i
i
i -
s
t
a
r
t
start
start) 。
题目数据保证 t a r g e t target target 存在于 n u m s nums nums 中。
示例 1
输入:nums = [1,2,3,4,5], target = 5, start = 3
输出:1
解释:nums[4] = 5 是唯一一个等于 target 的值,所以答案是 abs(4 - 3) = 1
示例 2
输入:nums = [1], target = 1, start = 0
输出:0
解释:nums[0] = 1 是唯一一个等于 target 的值,所以答案是 abs(0 - 0) = 1
提示:
1
≤
n
u
m
s
.
l
e
n
g
t
h
≤
1000
1 \leq nums.length \leq 1000
1≤nums.length≤1000
1
≤
n
u
m
s
[
i
]
≤
1
0
4
1 \leq nums[i] \leq 10^4
1≤nums[i]≤104
0
≤
s
t
a
r
t
<
n
u
m
s
.
l
e
n
g
t
h
0 \leq start < nums.length
0≤start<nums.length
t
a
r
g
e
t
target
target 存在于
n
u
m
s
nums
nums 中
class Solution {
public:
int getMinDistance(vector<int>& nums, int target, int start) {
int res = 1100;
int len = nums.size();
for(int i = 0; i < len; i++)
{
if(nums[i] == target)
res = min(res, abs(i-start));
}
return res;
}
};
将字符串拆分为递减的连续值
Leetcode 5747 将字符串拆分为递减的连续值
题目描述
给你一个仅由数字组成的字符串
s
s
s。
请你判断能否将
s
s
s 拆分成两个或者多个非空子字符串 ,使子字符串的数值 按降序排列,且每两个相邻子字符串的数值之差等于 1 。
例如,字符串 s s s = “0090089” 可以拆分成 [ " 0090 " , " 089 " ] ["0090", "089"] ["0090","089"],数值为 [ 90 , 89 ] [90,89] [90,89]。这些数值满足按降序排列,且相邻值相差 1 ,这种拆分方法可行。
另一个例子中,字符串
s
s
s = “001” 可以拆分成
[
"
0
"
,
"
01
"
]
["0", "01"]
["0","01"]、
[
"
00
"
,
"
1
"
]
["00", "1"]
["00","1"] 或
[
"
0
"
,
"
0
"
,
"
1
"
]
["0", "0", "1"]
["0","0","1"] 。然而,所有这些拆分方法都不可行,因为对应数值分别是
[
0
,
1
]
[0,1]
[0,1]、
[
0
,
1
]
[0,1]
[0,1] 和
[
0
,
0
,
1
]
[0,0,1]
[0,0,1] ,都不满足按降序排列的要求。
如果可以按要求拆分
s
s
s ,返回
t
r
u
e
true
true;否则,返回
f
a
l
s
e
false
false。
子字符串 是字符串中的一个连续字符序列。
示例 1
输入:s = "1234"
输出:false
解释:不存在拆分 s 的可行方法。
示例 2
输入:s = "050043"
输出:true
解释:s 可以拆分为 ["05", "004", "3"] ,对应数值为 [5,4,3] 。
满足按降序排列,且相邻值相差 1 。
示例 3
输入:s = "9080701"
输出:false
解释:不存在拆分 s 的可行方法。
示例 4
输入:s = "10009998"
输出:true
解释:s 可以拆分为 ["100", "099", "98"] ,对应数值为 [100,99,98] 。
满足按降序排列,且相邻值相差 1 。
提示:
1
≤
s
.
l
e
n
g
t
h
≤
20
1 \leq s.length \leq 20
1≤s.length≤20
s
s
s 仅由数字组成
解题思路
1.删除前导 0.
2.枚举的数的长度顶多是
s
.
s
i
z
e
(
)
+
1
>
>
1
s.size() + 1 >> 1
s.size()+1>>1
3.当
f
i
r
s
t
=
=
s
e
c
o
n
d
+
1
first == second + 1
first==second+1 时,
f
i
s
r
t
=
s
e
c
o
n
d
,
s
e
c
o
n
d
=
0
fisrt = second,second = 0
fisrt=second,second=0,当枚举到区间右端点末端时,当前长度的数是个合法方案。
4.当
s
e
c
o
n
d
>
=
f
i
s
r
t
second >= fisrt
second>=fisrt 时当前长度的枚举长度不存在合法方案,枚举长度加 1,然后重新计算
f
i
r
s
t
first
first,重新寻找
s
e
c
o
n
d
second
second
5.注意处理当
f
i
r
s
t
=
=
0
first == 0
first==0 时,区间右端点都是 0 也是一种合法方案。
class Solution {
public:
string s = "";
typedef long long ll;
bool splitString(string _s) {
int len = _s.size();
int pos = 0;
for(int i = 0; i < len; i++)
if(_s[i] == '0') pos++;
else break;
s = _s.substr(pos,len-pos);
if(s.size() <= 1) return false;
int n = s.size() + 1 >> 1;
for(int i = 1; i <= n; i++)
{
ll first = 0, second = 0;
for(int k = 0; k < i; k++) first = first*10 + (ll)(s[k] - '0');
for(int j = i; j < s.size(); j++)
{
while(second < first && j < s.size())
{
second = second * 10 + (ll)(s[j++] - '0');
if(second + 1 == first)
{
first = second;
second = 0;
if(first == 0) while(s[j] == '0' && j < s.size()) j++;
if(j == s.size()) return true;
}
else if(second >= first) j = s.size() + 1;
}
}
}
return false;
}
};
解题思路2:状态压缩
1.字符串长度为 20,最多划分成 19 段,枚举 1 ~
2
19
2^{19}
219,数据类型用
u
n
s
i
g
n
e
d
unsigned
unsigned
l
o
n
g
long
long
l
o
n
g
long
long,如果数据溢出是对
2
64
2^{64}
264 取模。
2.
2
19
2^{19}
219状态方案中寻找只要有一个状态满足题意就返回
t
r
u
e
true
true,否则返回
f
a
l
s
e
false
false。
3.每个状态枚举每一位,如果是 1 就是一条分割线,否则就不是。
class Solution {
public:
typedef unsigned long long ull;
bool splitString(string s) {
int n = s.size();
ull m = 1 << (ull)(n-1);
for(ull i = 1; i <= m; i++)
{
bool st = true;
ull pre = -1, now = s[0] - '0';
for(int j = 0; j < n - 1; j++)
{
if(i >> j & 1)
{
if(pre != -1 && now + 1 != pre)
{
st = false;
break;
}
pre = now;
now = s[j+1] - '0';
}
else now = now*10 + s[j+1] - '0';
}
if(pre != now + 1) st = false;
if(st) return true;
}
return false;
}
};
邻位交换的最小次数
Leetcode 5749 邻位交换的最小次数
题目描述
给你一个表示大整数的字符串
n
u
m
num
num ,和一个整数
k
k
k 。
如果某个整数是 n u m num num 中各位数字的一个排列且它的值大于num ,则称这个整数为妙数 。可能存在很多妙数,但是只需要关注 值最小 的那些。
例如,
n
u
m
num
num = “5489355142”:
第 1 个最小妙数是 “5489355214”
第 2 个最小妙数是 “5489355241”
第 3 个最小妙数是 “5489355412”
第 4 个最小妙数是 “5489355421”
返回要得到第
k
k
k 个 最小妙数 需要对
n
u
m
num
num 执行的 相邻位数字交换的最小次数 。
测试用例是按存在第
k
k
k 个最小妙数而生成的。
示例 1
输入:num = "5489355142", k = 4
输出:2
解释:第 4 个最小妙数是 "5489355421" ,要想得到这个数字:
- 交换下标 7 和下标 8 对应的位:"5489355142" -> "5489355412"
- 交换下标 8 和下标 9 对应的位:"5489355412" -> "5489355421"
示例 2
输入:num = "11112", k = 4
输出:4
解释:第 4 个最小妙数是 "21111" ,要想得到这个数字:
- 交换下标 3 和下标 4 对应的位:"11112" -> "11121"
- 交换下标 2 和下标 3 对应的位:"11121" -> "11211"
- 交换下标 1 和下标 2 对应的位:"11211" -> "12111"
- 交换下标 0 和下标 1 对应的位:"12111" -> "21111"
示例 3
输入:num = "00123", k = 1
输出:1
解释:第 1 个最小妙数是 "00132" ,要想得到这个数字:
- 交换下标 3 和下标 4 对应的位:"00123" -> "00132"
提示:
2
≤
n
u
m
.
l
e
n
g
t
h
≤
1000
2 \leq num.length \leq 1000
2≤num.length≤1000
1
≤
k
≤
1000
1 \leq k \leq 1000
1≤k≤1000
n
u
m
num
num 仅由数字组成
解题思路
- n e x t _ p e r m u t a t i o n next\_permutation next_permutation 求第 k k k 个排列。
- 原序列每个数有个下标,即 [0…n-1],在第 k k k 个排列中每个字符对应原来字符的下标一一对应。
- 求一下逆序对数量就是最后的交换次数。
class Solution {
public:
int getMinSwaps(string num, int k) {
string s = num;
while(k--) next_permutation(s.begin(),s.end());
int n = s.size();
int cnt[10] = {0}, a[1007] = {0};
for(int i = 0; i < n; i++)
{
int pre = num[i] - '0';
int out = 0;
cnt[pre]++;
for(int j = 0; j < n; j++)
if(s[j] - '0' == pre && ++out == cnt[pre])
a[j] = i, j = n;
}
int ans = 0;
for(int i = 0; i < n; i++)
for(int j = i + 1; j < n; j++)
if(a[i] > a[j]) ans++;
return ans;
}
};
包含每个查询的最小区间
Leetcode 1851 包含每个查询的最小区间
题目描述
给你一个二维整数数组
i
n
t
e
r
v
a
l
s
intervals
intervals ,其中
i
n
t
e
r
v
a
l
s
[
i
]
intervals[i]
intervals[i] =
[
l
e
f
t
i
,
r
i
g
h
t
i
]
[left_i, right_i]
[lefti,righti] 表示第
i
i
i 个区间开始于
l
e
f
t
i
left_i
lefti 、结束于
r
i
g
h
t
i
right_i
righti(包含两侧取值,闭区间)。区间的 长度 定义为区间中包含的整数数目,更正式地表达是
r
i
g
h
t
i
right_i
righti -
l
e
f
t
i
left_i
lefti + 1 。
再给你一个整数数组 q u e r i e s queries queries。第 j j j 个查询的答案是满足 l e f t i left_i lefti ≤ \leq ≤ q u e r i e s [ j ] queries[j] queries[j] ≤ \leq ≤ r i g h t i right_i righti 的长度最小区间 i i i 的长度 。如果不存在这样的区间,那么答案是 -1 。
以数组形式返回对应查询的所有答案。
示例 1
输入:intervals = [[1,4],[2,4],[3,6],[4,4]], queries = [2,3,4,5]
输出:[3,3,1,4]
解释:查询处理如下:
- Query = 2 :区间 [2,4] 是包含 2 的最小区间,答案为 4 - 2 + 1 = 3 。
- Query = 3 :区间 [2,4] 是包含 3 的最小区间,答案为 4 - 2 + 1 = 3 。
- Query = 4 :区间 [4,4] 是包含 4 的最小区间,答案为 4 - 4 + 1 = 1 。
- Query = 5 :区间 [3,6] 是包含 5 的最小区间,答案为 6 - 3 + 1 = 4 。
示例 2
输入:intervals = [[2,3],[2,5],[1,8],[20,25]], queries = [2,19,5,22]
输出:[2,-1,4,6]
解释:查询处理如下:
- Query = 2 :区间 [2,3] 是包含 2 的最小区间,答案为 3 - 2 + 1 = 2 。
- Query = 19:不存在包含 19 的区间,答案为 -1 。
- Query = 5 :区间 [2,5] 是包含 5 的最小区间,答案为 5 - 2 + 1 = 4 。
- Query = 22:区间 [20,25] 是包含 22 的最小区间,答案为 25 - 20 + 1 = 6
提示:
1
≤
i
n
t
e
r
v
a
l
s
.
l
e
n
g
t
h
≤
1
0
5
1 \leq intervals.length \leq10^5
1≤intervals.length≤105
1
≤
q
u
e
r
i
e
s
.
l
e
n
g
t
h
≤
1
0
5
1 \leq queries.length \leq 10^5
1≤queries.length≤105
q
u
e
r
i
e
s
[
i
]
.
l
e
n
g
t
h
=
=
2
queries[i].length == 2
queries[i].length==2
1
≤
l
e
f
t
i
<
=
r
i
g
h
t
i
≤
1
0
7
1 \leq lefti <= righti \leq 10^7
1≤lefti<=righti≤107
1
≤
q
u
e
r
i
e
s
[
j
]
≤
1
0
7
1 \leq queries[j] \leq 10^7
1≤queries[j]≤107
离散化+并查集
class Solution {
public:
vector<int> v, fa, w;
//并查集初始化
void Init(int x){
for(int i = 0; i <= x; i++) fa[i] = i, w[i] = -1;
}
//路径压缩
int find(int x){
return fa[x] = (fa[x] == x ? fa[x] : find(fa[x]));
}
//查询
int Query(int x){
return lower_bound(v.begin(),v.end(),x) - v.begin();
}
vector<int> minInterval(vector<vector<int>>& intervals, vector<int>& queries) {
for(auto& x : intervals) v.push_back(x[0]), v.push_back(x[1]);
for(auto x : queries) v.push_back(x);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
sort(intervals.begin(),intervals.end(),
[](vector<int>& x, vector<int>& y){
return x[1] - x[0] < y[1] - y[0];
});
int n = v.size();
fa.resize(n+7); w.resize(n+7);
Init(n);
for(auto& x : intervals){
int val = x[1] - x[0] + 1;
int l = Query(x[0]), r = Query(x[1]);
while(find(l) <= r){
l = find(l);
w[l] = val;
fa[l] = l + 1;
}
}
vector<int> ans;
for(auto x : queries) ans.push_back(w[Query(x)]);
return ans;
}
};