Minimum Operations to Make Every Element Palindromic solution and explanation
2 more videos on this problem
Leetcode 4053 | Minimum Operations to Make Every Element Palindromic | Leetcode weekly contest 519CodeWithMeGuys · 21:06 · 645 views
Minimum Operations to Make Every Element Palindromic | LeetCode 4053 | Precomputation Binary SearchManjeet Dhayal · 8:30 · 310 views
4053. Minimum Operations to Make Every Element Palindromic (Leetcode Medium)Programming Live with Larry · 23:50 · 15 views
The problem
You are given an integer array nums.
In one operation, you may choose an index i and either increment or decrement nums[i] by 2.
Return the minimum number of operations required to make every element in nums a positive palindrome. Different elements may be changed into different palindromic integers.
Example 1:
Input: nums = [10,12,14,16]
Output: 9
Explanation:
One optimal sequence of operations is:
- Decrement
nums[0]by 2 once to change it from 10 to 8. - Decrement
nums[1]by 2 twice to change it from 12 to 8. - Decrement
nums[2]by 2 three times to change it from 14 to 8. - Increment
nums[3]by 2 three times to change it from 16 to 22.
After 1 + 2 + 3 + 3 = 9 operations, nums = [8, 8, 8, 22], and every element is a positive palindromic integer.
It can be shown that fewer than 9 operations cannot achieve this.
Example 2:
Input: nums = [9,10,11,10]
Output: 2
Explanation:
Decrement nums[1] and nums[3] by 2 once each.
After 2 operations, nums = [9, 8, 11, 8], and every element is a positive palindromic integer.
At least one operation is needed for each of these two elements, so the minimum number of operations is 2.
Example 3:
Input: nums = [125]
Output: 2
Explanation:
Decrement nums[0] by 2 twice to change it from 125 to 121, which is a positive palindromic integer.
A single operation would change it to 123 or 127, neither of which is palindromic. Thus, the minimum number of operations is 2.
Constraints:
1 <= nums.length <= 1051 <= nums[i] <= 109
Approach overview
Problem Overview: You are given an array of integers. In one operation, you can increment or decrement any element by 1. The goal is to find the minimum number of operations required to make every element in the array a palindromic number.
Approach 1: Brute Force - Check All Palindromes (O(n * m * L))
For each element, generate palindromic numbers one by one and compute the absolute difference to find the nearest one. This requires iterating through a large range of numbers and checking each for palindromic property, which is extremely slow for large values. The key insight is that you only need the nearest palindrome, but without precomputation you end up scanning many candidates. This approach is only useful for understanding the problem, not for solving it efficiently.
Approach 2: Precompute Palindromes + Binary Search (O(n log n) time, O(m) space)
Precompute all palindromic numbers up to a reasonable upper bound (e.g., 10^6 or based on the maximum element in the array). Store them in a sorted list. For each element in the input array, use binary search to find the closest palindrome by checking the element at the insertion position and the one just before it. Take the minimum absolute difference between the element and these two candidate palindromes, and sum that over all elements. This is the optimal approach because binary search on a sorted list gives O(log m) lookup per element, and the precomputation is done only once. This is the approach you should use in interviews and in practice.
Recommended for interviews: Interviewers expect the precomputation + binary search solution. The brute force shows you understand the problem, but the optimal solution demonstrates that you can recognize the value of preprocessing and efficient lookup. Mentioning the tradeoff between precomputation time and query time is a strong signal. You can also mention that the sorted list of palindromes is a form of binary search on a static dataset, which is a common pattern in array problems.
Solution
Thinking
Each operation adds or subtracts
2, so parity never changes:nums[i]can only become a positive palindrome of the same parity. The elements are independent, and the answer is the sum of each value's distance to the nearest same-parity palindrome, divided by2.With
n = 10^5and values up to10^9, walking fromxby steps of2until a palindrome appears is too slow.Every palindrome is a mirrored prefix. Enumerating prefixes
1 ldots 10^5and forming both even-length and odd-length palindromes covers everything around10^9. Split them by parity, sort each list, and binary-search the nearest neighbor for everyx.
An operation increments or decrements an element by 2, so its parity is invariant and the target palindrome must have the same parity. The elements are independent: for each x, find the nearest same-parity positive palindrome p and add \lvert x - p \rvert / 2.
During preprocessing, enumerate prefixes i = 1, 2, ldots, 10^5 and let s be the decimal representation of i:
- Even-length palindrome:
s + reverse(s) - Odd-length palindrome:
s + reverse(s[:-1])
Store them in two lists by parity and sort each list. This range covers all palindromes with up to about 12 digits, which is enough for values up to 10^9.
For each x, binary-search the first palindrome that is at least x in the same-parity list, compare it with the previous one, and take the smaller distance divided by 2.
Let M be the number of palindromes (about 2 times 10^5). Preprocessing takes O(M log M) and each query takes O(log M). The overall time complexity is O(M log M + n log M), and the space complexity is O(M).
ps = [[], []]
for i in range(1, 10**5 + 1):
s = str(i)
t1 = s[::-1]
t2 = s[:-1][::-1]
x = int(s + t1)
ps[x & 1].append(x)
y = int(s + t2)
ps[y & 1].append(y)
for p in ps:
p.sort()
class Solution:
def minOperations(self, nums: list[int]) -> int:
ans = 0
for x in nums:
p = ps[x & 1]
i = bisect_left(p, x)
t = inf
if i < len(p):
t = p[i] - x
if i:
t = min(t, x - p[i - 1])
ans += t // 2
return ansclass Solution {
static List<Long>[] ps = new ArrayList[2];
static {
ps[0] = new ArrayList<>();
ps[1] = new ArrayList<>();
for (int i = 1; i <= 100000; i++) {
String s = String.valueOf(i);
String t1 = new StringBuilder(s).reverse().toString();
String t2 = new StringBuilder(s.substring(0, s.length() - 1)).reverse().toString();
long x = Long.parseLong(s + t1);
ps[(int) (x & 1)].add(x);
long y = Long.parseLong(s + t2);
ps[(int) (y & 1)].add(y);
}
ps[0].sort(Long::compare);
ps[1].sort(Long::compare);
}
public long minOperations(int[] nums) {
long ans = 0;
for (int x : nums) {
List<Long> p = ps[x & 1];
int l = 0, r = p.size();
while (l < r) {
int m = (l + r) >>> 1;
if (p.get(m) < x) {
l = m + 1;
} else {
r = m;
}
}
long t = Long.MAX_VALUE;
if (l < p.size()) {
t = p.get(l) - x;
}
if (l > 0) {
t = Math.min(t, (long) x - p.get(l - 1));
}
ans += t / 2;
}
return ans;
}
}class Solution {
public:
long long minOperations(vector<int>& nums) {
static vector<long long> ps[2];
if (ps[0].empty()) {
for (long long i = 1; i <= 100000; ++i) {
string s = to_string(i);
string t1 = s;
reverse(t1.begin(), t1.end());
string t2 = s.substr(0, s.size() - 1);
reverse(t2.begin(), t2.end());
long long x = stoll(s + t1);
ps[x & 1].push_back(x);
long long y = stoll(s + t2);
ps[y & 1].push_back(y);
}
sort(ps[0].begin(), ps[0].end());
sort(ps[1].begin(), ps[1].end());
}
long long ans = 0;
for (int x : nums) {
auto& p = ps[x & 1];
auto it = lower_bound(p.begin(), p.end(), x);
long long t = LLONG_MAX;
if (it != p.end()) {
t = *it - x;
}
if (it != p.begin()) {
t = min(t, (long long) x - *prev(it));
}
ans += t / 2;
}
return ans;
}
};const ps: number[][] = [[], []];
for (let i = 1; i <= 10 ** 5; i++) {
const s = String(i);
const t1 = [...s].reverse().join('');
const t2 = [...s.slice(0, -1)].reverse().join('');
const x = Number(s + t1);
ps[x & 1].push(x);
const y = Number(s + t2);
ps[y & 1].push(y);
}
ps[0].sort((a, b) => a - b);
ps[1].sort((a, b) => a - b);
function minOperations(nums: number[]): number {
let ans = 0;
for (const x of nums) {
const p = ps[x & 1];
let l = 0;
let r = p.length;
while (l < r) {
const m = (l + r) >> 1;
if (p[m] < x) {
l = m + 1;
} else {
r = m;
}
}
let t = Number.MAX_SAFE_INTEGER;
if (l < p.length) {
t = p[l] - x;
}
if (l > 0) {
t = Math.min(t, x - p[l - 1]);
}
ans += Math.floor(t / 2);
}
return ans;
}var ps [2][]int64
func init() {
for i := int64(1); i <= 100000; i++ {
s := strconv.FormatInt(i, 10)
t1 := reverse(s)
t2 := reverse(s[:len(s)-1])
x, _ := strconv.ParseInt(s+t1, 10, 64)
ps[x&1] = append(ps[x&1], x)
y, _ := strconv.ParseInt(s+t2, 10, 64)
ps[y&1] = append(ps[y&1], y)
}
sort.Slice(ps[0], func(a, b int) bool { return ps[0][a] < ps[0][b] })
sort.Slice(ps[1], func(a, b int) bool { return ps[1][a] < ps[1][b] })
}
func reverse(s string) string {
b := []byte(s)
for i, j := 0, len(b)-1; i < j; i, j = i+1, j-1 {
b[i], b[j] = b[j], b[i]
}
return string(b)
}
func minOperations(nums []int) int64 {
var ans int64
for _, x := range nums {
p := ps[x&1]
i := sort.Search(len(p), func(i int) bool { return p[i] >= int64(x) })
t := int64(1 << 62)
if i < len(p) {
t = p[i] - int64(x)
}
if i > 0 {
t = min(t, int64(x)-p[i-1])
}
ans += t / 2
}
return ans
}Complexity analysis
| Approach | Time | Space | When to Use |
|---|---|---|---|
| Brute Force - Check All Palindromes | O(n * m * L) | O(1) | Only for understanding the problem, not practical |
| Precompute Palindromes + Binary Search | O(n log m + m) | O(m) | General case, optimal for large arrays and values |
Frequently asked questions
Is Minimum Operations to Make Every Element Palindromic easy or hard?
It is rated Medium on FleetCode with a 14.9% acceptance rate. The difficulty comes from recognizing that you need to precompute palindromes and apply binary search, rather than checking each number individually.
Minimum Operations to Make Every Element Palindromic Python/Java solution
In Python, precompute palindromes into a sorted list and use the bisect module for binary search. In Java, use Arrays.binarySearch on an int array of palindromes. Both approaches run in O(n log m) time and are available on FleetCode in Python, Java, C++, Go, and TypeScript.
How to solve Minimum Operations to Make Every Element Palindromic in O(n log n)?
Precompute all palindromic numbers up to the maximum possible value in the array and store them in a sorted list. Then for each element, use binary search to find the closest palindrome by checking the insertion point and the element before it. Sum the minimum absolute differences to get the answer.
What is the best approach for Minimum Operations to Make Every Element Palindromic?
The best approach is to precompute all palindromic numbers up to a reasonable upper bound, store them in a sorted list, and then for each element use binary search to find the closest palindrome. This gives O(n log m) time complexity, where n is the array length and m is the number of precomputed palindromes.
Is Minimum Operations to Make Every Element Palindromic asked at Google/Amazon/Meta?
This problem is tagged under Array and Binary Search on FleetCode, and similar palindrome-manipulation problems appear in interviews at top companies. The core technique of precomputing candidates and using binary search is a common interview pattern at Google, Amazon, and Meta.
What data structure is used in Minimum Operations to Make Every Element Palindromic?
A sorted array or list is used to store all precomputed palindromic numbers. Binary search is then applied on this sorted list to find the closest palindrome for each element in the input array.
What is the time complexity of Minimum Operations to Make Every Element Palindromic?
The optimal solution using precomputed palindromes and binary search runs in O(n log m) time, where n is the number of elements and m is the number of precomputed palindromes. The space complexity is O(m) to store the sorted list of palindromes.
