Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Move from brute-force thinking to an efficient approach using array strategy.
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 also given an integer m. Find the latest step at which there exists a group of ones of length m. A group of ones is a contiguous substring of 1's 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.
Constraints:
n == arr.length1 <= m <= n <= 1051 <= arr[i] <= narr are distinct.Problem summary: 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 also given an integer m. Find the latest step at which there exists a group of ones of length m. A group of ones is a contiguous substring of 1's 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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Hash Map · Binary Search
[3,5,1,2,4] 1
[3,1,5,4,2] 2
Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1562: Find Latest Group of Size M
class Solution {
private int[] p;
private int[] size;
public int findLatestStep(int[] arr, int m) {
int n = arr.length;
if (m == n) {
return n;
}
boolean[] vis = new boolean[n];
p = new int[n];
size = new int[n];
for (int i = 0; i < n; ++i) {
p[i] = i;
size[i] = 1;
}
int ans = -1;
for (int i = 0; i < n; ++i) {
int v = arr[i] - 1;
if (v > 0 && vis[v - 1]) {
if (size[find(v - 1)] == m) {
ans = i;
}
union(v, v - 1);
}
if (v < n - 1 && vis[v + 1]) {
if (size[find(v + 1)] == m) {
ans = i;
}
union(v, v + 1);
}
vis[v] = true;
}
return ans;
}
private int find(int x) {
if (p[x] != x) {
p[x] = find(p[x]);
}
return p[x];
}
private void union(int a, int b) {
int pa = find(a), pb = find(b);
if (pa == pb) {
return;
}
p[pa] = pb;
size[pb] += size[pa];
}
}
// Accepted solution for LeetCode #1562: Find Latest Group of Size M
func findLatestStep(arr []int, m int) int {
n := len(arr)
if m == n {
return n
}
p := make([]int, n)
size := make([]int, n)
vis := make([]bool, n)
for i := range p {
p[i] = i
size[i] = 1
}
var find func(int) int
find = func(x int) int {
if p[x] != x {
p[x] = find(p[x])
}
return p[x]
}
union := func(a, b int) {
pa, pb := find(a), find(b)
if pa == pb {
return
}
p[pa] = pb
size[pb] += size[pa]
}
ans := -1
for i, v := range arr {
v--
if v > 0 && vis[v-1] {
if size[find(v-1)] == m {
ans = i
}
union(v, v-1)
}
if v < n-1 && vis[v+1] {
if size[find(v+1)] == m {
ans = i
}
union(v, v+1)
}
vis[v] = true
}
return ans
}
# Accepted solution for LeetCode #1562: Find Latest Group of Size M
class Solution:
def findLatestStep(self, arr: List[int], m: int) -> int:
def find(x):
if p[x] != x:
p[x] = find(p[x])
return p[x]
def union(a, b):
pa, pb = find(a), find(b)
if pa == pb:
return
p[pa] = pb
size[pb] += size[pa]
n = len(arr)
if m == n:
return n
vis = [False] * n
p = list(range(n))
size = [1] * n
ans = -1
for i, v in enumerate(arr):
v -= 1
if v and vis[v - 1]:
if size[find(v - 1)] == m:
ans = i
union(v, v - 1)
if v < n - 1 and vis[v + 1]:
if size[find(v + 1)] == m:
ans = i
union(v, v + 1)
vis[v] = True
return ans
// Accepted solution for LeetCode #1562: Find Latest Group of Size M
struct Solution;
use std::collections::HashMap;
struct UnionFind {
parent: Vec<usize>,
size: Vec<usize>,
group: HashMap<usize, usize>,
n: usize,
}
impl UnionFind {
fn new(n: usize) -> Self {
let parent = (0..n).collect();
let size = vec![0; n];
let group = HashMap::new();
UnionFind {
parent,
size,
group,
n,
}
}
fn set_one(&mut self, i: usize) {
self.size[i] = 1;
*self.group.entry(1).or_default() += 1;
}
fn find(&mut self, i: usize) -> usize {
let j = self.parent[i];
if i == j {
i
} else {
let k = self.find(j);
self.parent[i] = k;
k
}
}
fn union(&mut self, mut i: usize, mut j: usize) {
i = self.find(i);
j = self.find(j);
let a = self.size[i];
let b = self.size[j];
let c = a + b;
*self.group.entry(a).or_default() -= 1;
*self.group.entry(b).or_default() -= 1;
*self.group.entry(c).or_default() += 1;
if i != j {
self.parent[i] = j;
self.size[j] += self.size[i];
self.n -= 1;
}
}
}
impl Solution {
fn find_latest_step(arr: Vec<i32>, m: i32) -> i32 {
let m = m as usize;
let n = arr.len();
let mut values = vec![0; n];
let mut res = -1;
let mut uf = UnionFind::new(n);
for i in 0..n {
let j = (arr[i] - 1) as usize;
values[j] = 1;
uf.set_one(j);
if j > 0 && values[j - 1] == 1 {
uf.union(j - 1, j);
}
if j + 1 < n && values[j + 1] == 1 {
uf.union(j, j + 1);
}
if *uf.group.entry(m).or_default() > 0 {
res = (i + 1) as i32;
}
}
res
}
}
#[test]
fn test() {
let arr = vec![3, 5, 1, 2, 4];
let m = 1;
let res = 4;
assert_eq!(Solution::find_latest_step(arr, m), res);
}
// Accepted solution for LeetCode #1562: Find Latest Group of Size M
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1562: Find Latest Group of Size M
// class Solution {
// private int[] p;
// private int[] size;
//
// public int findLatestStep(int[] arr, int m) {
// int n = arr.length;
// if (m == n) {
// return n;
// }
// boolean[] vis = new boolean[n];
// p = new int[n];
// size = new int[n];
// for (int i = 0; i < n; ++i) {
// p[i] = i;
// size[i] = 1;
// }
// int ans = -1;
// for (int i = 0; i < n; ++i) {
// int v = arr[i] - 1;
// if (v > 0 && vis[v - 1]) {
// if (size[find(v - 1)] == m) {
// ans = i;
// }
// union(v, v - 1);
// }
// if (v < n - 1 && vis[v + 1]) {
// if (size[find(v + 1)] == m) {
// ans = i;
// }
// union(v, v + 1);
// }
// vis[v] = true;
// }
// return ans;
// }
//
// private int find(int x) {
// if (p[x] != x) {
// p[x] = find(p[x]);
// }
// return p[x];
// }
//
// private void union(int a, int b) {
// int pa = find(a), pb = find(b);
// if (pa == pb) {
// return;
// }
// p[pa] = pb;
// size[pb] += size[pa];
// }
// }
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Zero-count keys stay in map and break distinct/count constraints.
Usually fails on: Window/map size checks are consistently off by one.
Fix: Delete keys when count reaches zero.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.