Given a positive 32-bit integer n
, find the smallest integer that is strictly greater than n
and contains exactly the same digits as n
. If no such integer exists, return -1
.
n
(no digit can be repeated or omitted).-1
.
Example:
Input: n = 12443322
Output: 13222344
At first glance, one might consider generating all permutations of the digits of n
, sorting them, and picking the next greater one. However, this brute-force approach is highly inefficient due to the factorial growth in possibilities.
The problem is essentially about finding the "next lexicographical permutation" of the digits of n
. This is a well-known problem that can be solved efficiently by manipulating the digits in place, similar to how you would find the next permutation in a sequence.
The main idea is to identify the rightmost place where you can make the number bigger by swapping digits, and then rearrange the remaining digits to make the smallest possible number that is still larger than the original.
We use the "next permutation" algorithm, which works as follows:
i
where digits[i] < digits[i+1]
. This is the pivot point where we can make the number larger.
-1
.
i
that is larger than digits[i]
: Swap these two digits.
i
: This ensures the smallest possible number is formed with the remaining digits.
-1
.
This approach is efficient and avoids unnecessary permutations.
Let's walk through the example where n = 12443322
:
[1, 2, 4, 4, 3, 3, 2, 2]
2
(from index 2 onwards). That is 3
at index 5.
[1, 3, 4, 4, 3, 2, 2, 2]
[1, 3, 2, 2, 2, 3, 4, 4]
13222344
, which is the answer.
O(n!)
for n
digits, which is infeasible for anything but very small numbers.
O(n)
time and uses O(n)
space for the digit array, where n
is the number of digits in n
. Each step (finding pivot, finding swap candidate, reversing) is linear in the number of digits.
By recognizing the problem as one of finding the next lexicographical permutation, we avoid brute-force permutation generation. The efficient "next permutation" algorithm finds the next greater number using the same digits in linear time by identifying a pivot, swapping, and reversing. This approach is both elegant and optimal for this class of problems.
class Solution:
def nextGreaterElement(self, n: int) -> int:
digits = list(str(n))
i = len(digits) - 2
# Step 1: Find first decreasing digit from right
while i >= 0 and digits[i] >= digits[i+1]:
i -= 1
if i == -1:
return -1
# Step 2: Find the smallest digit on right side > digits[i]
j = len(digits) - 1
while digits[j] <= digits[i]:
j -= 1
# Step 3: Swap
digits[i], digits[j] = digits[j], digits[i]
# Step 4: Reverse the right part
digits[i+1:] = reversed(digits[i+1:])
res = int(''.join(digits))
return res if res <= 2**31 - 1 else -1
class Solution {
public:
int nextGreaterElement(int n) {
string digits = to_string(n);
int i = digits.size() - 2;
// Step 1: Find first decreasing digit from right
while (i >= 0 && digits[i] >= digits[i+1]) {
i--;
}
if (i == -1) return -1;
// Step 2: Find the smallest digit on right side > digits[i]
int j = digits.size() - 1;
while (digits[j] <= digits[i]) {
j--;
}
// Step 3: Swap
swap(digits[i], digits[j]);
// Step 4: Reverse the right part
reverse(digits.begin() + i + 1, digits.end());
long res = stol(digits);
return (res <= INT_MAX) ? res : -1;
}
};
class Solution {
public int nextGreaterElement(int n) {
char[] digits = Integer.toString(n).toCharArray();
int i = digits.length - 2;
// Step 1: Find first decreasing digit from right
while (i >= 0 && digits[i] >= digits[i+1]) {
i--;
}
if (i == -1) return -1;
// Step 2: Find the smallest digit on right side > digits[i]
int j = digits.length - 1;
while (digits[j] <= digits[i]) {
j--;
}
// Step 3: Swap
char temp = digits[i];
digits[i] = digits[j];
digits[j] = temp;
// Step 4: Reverse the right part
int left = i + 1, right = digits.length - 1;
while (left < right) {
char t = digits[left];
digits[left] = digits[right];
digits[right] = t;
left++;
right--;
}
long res = Long.parseLong(new String(digits));
return (res <= Integer.MAX_VALUE) ? (int)res : -1;
}
}
var nextGreaterElement = function(n) {
let digits = Array.from(String(n), Number);
let i = digits.length - 2;
// Step 1: Find first decreasing digit from right
while (i >= 0 && digits[i] >= digits[i+1]) {
i--;
}
if (i === -1) return -1;
// Step 2: Find the smallest digit on right side > digits[i]
let j = digits.length - 1;
while (digits[j] <= digits[i]) {
j--;
}
// Step 3: Swap
[digits[i], digits[j]] = [digits[j], digits[i]];
// Step 4: Reverse the right part
let left = i + 1, right = digits.length - 1;
while (left < right) {
[digits[left], digits[right]] = [digits[right], digits[left]];
left++;
right--;
}
let res = parseInt(digits.join(''), 10);
return res <= 0x7FFFFFFF ? res : -1;
};