Formatted question description: https://leetcode.ca/all/1562.html

1562. Find Latest Group of Size M (Medium)

Given an array arr that represents a permutation of numbers from 1 to n. You have a binary string of size n that initially has all its bits set to zero.

At each step i (assuming both the binary string and arr are 1-indexed) from 1 to n, the bit at position arr[i] is set to 1. You are given an integer m and you need to find the latest step at which there exists a group of ones of length m. A group of ones is a contiguous substring of 1s such that it cannot be extended in either direction.

Return the latest step at which there exists a group of ones of length exactly m. If no such group exists, return -1.

 

Example 1:

Input: arr = [3,5,1,2,4], m = 1
Output: 4
Explanation:
Step 1: "00100", groups: ["1"]
Step 2: "00101", groups: ["1", "1"]
Step 3: "10101", groups: ["1", "1", "1"]
Step 4: "11101", groups: ["111", "1"]
Step 5: "11111", groups: ["11111"]
The latest step at which there exists a group of size 1 is step 4.

Example 2:

Input: arr = [3,1,5,4,2], m = 2
Output: -1
Explanation:
Step 1: "00100", groups: ["1"]
Step 2: "10100", groups: ["1", "1"]
Step 3: "10101", groups: ["1", "1", "1"]
Step 4: "10111", groups: ["1", "111"]
Step 5: "11111", groups: ["11111"]
No group of size 2 exists during any step.

Example 3:

Input: arr = [1], m = 1
Output: 1

Example 4:

Input: arr = [2,1], m = 2
Output: 2

 

Constraints:

  • n == arr.length
  • 1 <= n <= 10^5
  • 1 <= arr[i] <= n
  • All integers in arr are distinct.
  • 1 <= m <= arr.length

Related Topics:
Binary Search

Solution 1. Data on Interval’s Edge

We store the length information on the edge nodes of the intervals. When merging intervals, we only need to update the new edge nodes since they are the only ones that we’ll use later.

// OJ: https://leetcode.com/problems/find-latest-group-of-size-m/

// Time: O(N)
// Space: O(1)
// Ref: https://leetcode.com/problems/find-latest-group-of-size-m/discuss/806786/JavaC%2B%2BPython-Count-the-Length-of-Groups-O(N)
class Solution {
public:
    int findLatestStep(vector<int>& A, int m) {
        int N = A.size(), ans = -1;
        if (N == m) return N;
        vector<int> len(N + 2);
        for (int i = 0; i < N; ++i) {
            int n = A[i], left = len[n - 1], right = len[n + 1];
            len[n - left] = len[n + right] = left + right + 1;
            if (left == m || right == m) ans = i;
        }
        return ans;
    }
};

Solution 2. UnionFind

// OJ: https://leetcode.com/problems/find-latest-group-of-size-m/

// Time: O(N)
// Space: O(N)
class Solution {
    vector<int> id, size;
    int cnt = 0;
    int find(int x) {
        return id[x] == x ? x : (id[x] = find(id[x]));
    }
    void connect(int x, int y, int m) {
        int p = find(x), q = find(y);
        if (size[q] == m) --cnt;
        size[p] += size[q];
        id[q] = p;
    }
public:
    int findLatestStep(vector<int>& A, int m) {
        int N = A.size(), ans = -1;
        id.assign(N, 0);
        size.assign(N, 0);
        iota(begin(id), end(id), 0);
        for (int i = 0; i < N; ++i) {
            int n = A[i] - 1;
            size[n] = 1;
            if (n - 1 >= 0 && size[n - 1]) connect(n, n - 1, m);
            if (n + 1 < N && size[n + 1]) connect(n, n + 1, m);
            if (size[n] == m) ++cnt;
            if (cnt) ans = i + 1;
        }
        return ans;
    }
};

Java

class Solution {
    public int findLatestStep(int[] arr, int m) {
        int length = arr.length;
        TreeMap<Integer, Integer> groupMap = new TreeMap<Integer, Integer>();
        groupMap.put(1, length);
        Map<Integer, Integer> lengthMap = new HashMap<Integer, Integer>();
        lengthMap.put(length, 1);
        for (int i = length - 1; i >= 0; i--) {
            if (lengthMap.containsKey(m))
                return i + 1;
            int index = arr[i];
            int start = groupMap.floorKey(index);
            int end = groupMap.get(start);
            int groupLength = end - start + 1;
            if (index == start && index == end) {
                groupMap.remove(start);
                int count = lengthMap.get(groupLength) - 1;
                if (count == 0)
                    lengthMap.remove(groupLength);
                else
                    lengthMap.put(1, count);
            } else if (index == start) {
                groupMap.put(start + 1, end);
                groupMap.remove(start);
                int prevCount = lengthMap.get(groupLength) - 1;
                if (prevCount == 0)
                    lengthMap.remove(groupLength);
                else
                    lengthMap.put(groupLength, prevCount);
                int newLength = groupLength - 1;
                int newCount = lengthMap.getOrDefault(newLength, 0) + 1;
                lengthMap.put(newLength, newCount);
            } else if (index == end) {
                groupMap.put(start, end - 1);
                int prevCount = lengthMap.get(groupLength) - 1;
                if (prevCount == 0)
                    lengthMap.remove(groupLength);
                else
                    lengthMap.put(groupLength, prevCount);
                int newLength = groupLength - 1;
                int newCount = lengthMap.getOrDefault(newLength, 0) + 1;
                lengthMap.put(newLength, newCount);
            } else {
                groupMap.put(start, index - 1);
                groupMap.put(index + 1, end);
                int prevCount = lengthMap.get(groupLength) - 1;
                if (prevCount == 0)
                    lengthMap.remove(groupLength);
                else
                    lengthMap.put(groupLength, prevCount);
                int newLength1 = index - start, newLength2 = end - index;
                int newCount1 = lengthMap.getOrDefault(newLength1, 0) + 1;
                lengthMap.put(newLength1, newCount1);
                int newCount2 = lengthMap.getOrDefault(newLength2, 0) + 1;
                lengthMap.put(newLength2, newCount2);
            }
        }
        return -1;
    }
}

All Problems

All Solutions