leetcode 1562. 查找大小为 M 的最新分组 并查集维护连续区间 好题

  1. 查找大小为 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

问最后一步有连续m1的是第几步 ?

  • 并查集维护连续区间,并维护联通块大小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 



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值