- 查找大小为 M 的最新分组
给你一个数组 arr ,该数组表示一个从 1 到 n 的数字排列。有一个长度为 n 的二进制字符串,该字符串上的所有位最初都设置为 0 。
在从 1 到 n 的每个步骤 i 中(假设二进制字符串和 arr 都是从 1 开始索引的情况下),二进制字符串上位于位置 arr[i] 的位将会设为 1 。
给你一个整数 m ,请你找出二进制字符串上存在长度为 m 的一组 1 的最后步骤。一组 1 是一个连续的、由 1 组成的子串,且左右两边不再有可以延伸的 1 。
返回存在长度 恰好 为 m 的 一组 1 的最后步骤。如果不存在这样的步骤,请返回 -1 。
示例 1:
输入:arr = [3,5,1,2,4], m = 1
输出:4
解释:
步骤 1:“00100”,由 1 构成的组:[“1”]
步骤 2:“00101”,由 1 构成的组:[“1”, “1”]
步骤 3:“10101”,由 1 构成的组:[“1”, “1”, “1”]
步骤 4:“11101”,由 1 构成的组:[“111”, “1”]
步骤 5:“11111”,由 1 构成的组:[“11111”]
存在长度为 1 的一组 1 的最后步骤是步骤 4 。
示例 2:
输入:arr = [3,1,5,4,2], m = 2
输出:-1
解释:
步骤 1:“00100”,由 1 构成的组:[“1”]
步骤 2:“10100”,由 1 构成的组:[“1”, “1”]
步骤 3:“10101”,由 1 构成的组:[“1”, “1”, “1”]
步骤 4:“10111”,由 1 构成的组:[“1”, “111”]
步骤 5:“11111”,由 1 构成的组:[“11111”]
不管是哪一步骤都无法形成长度为 2 的一组 1 。
示例 3:
输入:arr = [1], m = 1
输出:1
示例 4:
输入:arr = [2,1], m = 2
输出:2
提示:
n == arr.length
1 <= n <= 10^5
1 <= arr[i] <= n
arr 中的所有整数 互不相同
1 <= m <= arr.length
leetcode 1562. 查找大小为 M 的最新分组 (维护连续区间)我的代码
给定一个不重复数组,和一个全
0
字符串str
,和数字m
,从前往后1到n把str[ a[i] ]
设置成1
,问最后一步有连续
m
个1
的是第几步 ?
- 并查集维护连续区间,并维护联通块大小
size
- 每次设置一个位置
a[i]
为1
时,应该把左右两端a[i]-1和a[i]+1
并成一个联通块(前提是左右已经是1了) - 每次
union_xy
后记录a[i]
所在联通块的长度计数+1
,即cnt[sz[fa(a[i])]]++
#define debug
#ifdef debug
#include <time.h>
#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>
#define MAXN ((int)1e5+7)
#define ll long long int
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)
using namespace std;
#define show(x...) \
do { \
cout << "\033[31;1m " << #x << " -> "; \
err(x); \
} while (0)
void err() { cout << "\033[39;0m" << endl; }
template<typename T, typename... A>
void err(T a, A... x) { cout << a << ' '; err(x...); }
namespace FastIO{
char print_f[105];
void read() {}
void print() { putchar('\n'); }
template <typename T, typename... T2>
inline void read(T &x, T2 &... oth) {
x = 0;
char ch = getchar();
ll f = 1;
while (!isdigit(ch)) {
if (ch == '-') f *= -1;
ch = getchar();
}
while (isdigit(ch)) {
x = x * 10 + ch - 48;
ch = getchar();
}
x *= f;
read(oth...);
}
template <typename T, typename... T2>
inline void print(T x, T2... oth) {
ll p3=-1;
if(x<0) putchar('-'), x=-x;
do{
print_f[++p3] = x%10 + 48;
} while(x/=10);
while(p3>=0) putchar(print_f[p3--]);
putchar(' ');
print(oth...);
}
} // namespace FastIO
using FastIO::print;
using FastIO::read;
int pre[MAXN], cnt[MAXN]/*cnt[i]存放长度为i的联通块个数*/, sz[MAXN], vis[MAXN];
int fa(int x) { return ( pre[x]==x ? x : (pre[x]=fa(pre[x])) ); }
void union_xy(int x, int y) {
x = fa(x), y = fa(y);
if(x ^ y) {
cnt[sz[y]] --, cnt[sz[x]] --; //由于左右被打通,所以左右的长度计数都要减小 1
sz[x] += sz[y];
cnt[sz[x]] ++;
pre[y] = x;
}
}
#define cls(x) (memset(x, 0, sizeof(x)))
class Solution {
public:
int findLatestStep(vector<int>& arr, int M) {
int n = arr.size(), timer = 0, ans = -1;
for(int i=1; i<=(n+1); i++) //一定要初始化到 n + 1
pre[i] = i, sz[i] = 1, cnt[i] = vis[i] = 0;
for(auto i : arr) {
int L = i - 1, R = i + 1;
vis[i] = true;
cnt[1] ++; //这一步不能少,一少就 WA
if(vis[L]) union_xy(L, i);
if(vis[R]) union_xy(i, R);
++ timer;
if(cnt[M]) ans = timer;
}
return ans;
}
};
#ifdef debug
signed main() {
vector<int> vec = { 3, 1, 2 };
int m = 1;
Solution s;
cout << s.findLatestStep(vec, m) << endl;
return 0;
}
#endif