#2983
Hard Algorithms Palindrome rearrangement queries
Hash Table String Prefix Sum
24.8% acceptance
Feb 25, 2026
98
27
You are given a 0-indexed string s having an even length n.
You are also given a 0-indexed 2D integer array, queries, where queries[i] = [ai, bi, ci, di].
For each query i, you are allowed to perform the following operations:
Rearrange the characters within the substring s[ai:bi], where 0 <= ai <= bi < n / 2.
Rearrange the characters within the substring s[ci:di], where n / 2 <= ci <= di < n.
For each query, your task is to determine whether it is possible to make s a palindrome by performing the operations.
Each query is answered independently of the others.
Return a 0-indexed array answer, where answer[i] == true if it is possible to make s a palindrome by performing operations specified by the ith query, and false otherwise.
A substring is a contiguous sequence of characters within a string.
s[x:y] represents the substring consisting of characters from the index x to index y in s, both inclusive.
Solution
Rust
Time O(n²)
Space O(n)
impl Solution {
pub fn can_make_palindrome_queries(s: String, queries: Vec<Vec<i32>>) -> Vec<bool> {
let n = s.len();
let half = n / 2;
let bs = s.as_bytes();
// pf[i][c] = count of char c in s[0..i-1] (first half, i in 0..=half)
// pr[i][c] = count of char c in s[n-1..n-1-i] (second-half mirrors of first-half [0..i-1])
// i.e., pr[i+1][c] = pr[i][c] + count(s[n-1-i] == c)
// mm[i] = count of mismatched pairs (j, n-1-j) for j in [0, i-1]
let mut pf = vec![[0i32; 26]; half + 1];
let mut pr = vec![[0i32; 26]; half + 1];
let mut mm = vec![0i32; half + 1];
for i in 0..half {
pf[i + 1] = pf[i];
pf[i + 1][(bs[i] - b'a') as usize] += 1;
pr[i + 1] = pr[i];
pr[i + 1][(bs[n - 1 - i] - b'a') as usize] += 1;
mm[i + 1] = mm[i] + if bs[i] != bs[n - 1 - i] { 1 } else { 0 };
}
let freq_first = |a: usize, b: usize| -> [i32; 26] {
let mut f = [0i32; 26];
for c in 0..26 { f[c] = pf[b + 1][c] - pf[a][c]; }
f
};
// freq of second-half mirrors of first-half positions [a..b]
let freq_mir = |a: usize, b: usize| -> [i32; 26] {
let mut f = [0i32; 26];
for c in 0..26 { f[c] = pr[b + 1][c] - pr[a][c]; }
f
};
let mm_range = |a: usize, b: usize| -> i32 {
if a > b { 0 } else { mm[b + 1] - mm[a] }
};
let mut result = Vec::with_capacity(queries.len());
for q in &queries {
let (a, b) = (q[0] as usize, q[1] as usize);
let (c, d) = (q[2] as usize, q[3] as usize);
// Mirror of second-half [c, d] in first-half: [n-1-d, n-1-c]
let mr_lo = n - 1 - d;
let mr_hi = n - 1 - c;
// Check mismatches outside L=[a,b] ∪ mirR=[mr_lo, mr_hi]
let total_mm = mm[half];
let mm_l = mm_range(a, b);
let mm_mirr = mm_range(mr_lo, mr_hi);
let ov_lo = a.max(mr_lo);
let ov_hi = b.min(mr_hi);
let mm_ov = if ov_lo <= ov_hi { mm_range(ov_lo, ov_hi) } else { 0 };
let mm_union = mm_l + mm_mirr - mm_ov;
if total_mm != mm_union {
result.push(false);
continue;
}
// Character availability check
// fl: characters available from first-half [a,b] (can be rearranged)
let fl = freq_first(a, b);
// fr: characters available from second-half mirrors of [mr_lo, mr_hi]
let fr = freq_mir(mr_lo, mr_hi);
// Required from fl: second-half chars at mirror positions of (L \ mirR)
// Positions in L but not mirR: [a, min(b, mr_lo-1)] and [max(a, mr_hi+1), b]
let mut req_l = [0i32; 26];
// part of L before mirR: [a, mr_lo-1]
if a < mr_lo {
let hi = (mr_lo - 1).min(b);
if a <= hi {
let f = freq_mir(a, hi);
for c in 0..26 { req_l[c] += f[c]; }
}
}
// part of L after mirR: [max(a, mr_hi+1), b]
if mr_hi < b {
let lo = (mr_hi + 1).max(a);
if lo <= b {
let f = freq_mir(lo, b);
for c in 0..26 { req_l[c] += f[c]; }
}
}
// Required from fr: first-half chars at (mirR \ L) positions
// Positions in mirR but not L: [mr_lo, a-1] and [b+1, mr_hi]
let mut req_r = [0i32; 26];
// part of mirR before L: [mr_lo, a-1]
if mr_lo < a {
let hi = (a - 1).min(mr_hi);
if mr_lo <= hi {
let f = freq_first(mr_lo, hi);
for c in 0..26 { req_r[c] += f[c]; }
}
}
// part of mirR after L: [max(mr_lo, b+1), mr_hi]
if b < mr_hi {
let lo = (b + 1).max(mr_lo);
if lo <= mr_hi {
let f = freq_first(lo, mr_hi);
for c in 0..26 { req_r[c] += f[c]; }
}
}
// Check fl can provide req_l and fr can provide req_r
let mut leftover_l = fl;
let mut leftover_r = fr;
let mut ok = true;
for c in 0..26 {
leftover_l[c] -= req_l[c];
if leftover_l[c] < 0 { ok = false; break; }
}
if ok {
for c in 0..26 {
leftover_r[c] -= req_r[c];
if leftover_r[c] < 0 { ok = false; break; }
}
}
if ok {
for c in 0..26 {
if leftover_l[c] != leftover_r[c] { ok = false; break; }
}
}
result.push(ok);
}
result
}
}