Next smaller number with the same digits (4kyu)
Description
Write a function that takes a positive integer and returns the next smaller positive integer containing the same digits.
For example:
next_smaller(21) == Some(12)
next_smaller(531) == Some(513)
next_smaller(2071) == Some(2017)
Return -1 (for Haskell
: return Nothing
, for Rust
: return None
), when there is no smaller number that contains the same digits. Also return -1 when the next smaller number with the same digits would require the leading digit to be zero.
next_smaller(9) == None
next_smaller(135) == None
next_smaller(1027) == None // 0721 is out since we don't write numbers with leading zeros
- some tests will include very large numbers.
- test data only employs positive integers.
Solution
The step of finding next smaller number:
take num = 32514
as an example
- Find the position
i
of the first digit from lower to upper place that is smaller than its right dight, goti=3
. - If
i==0
, the num has no next smaller number. - Find the position
j
of the first digit that is smaller thatnum[i-1]
, which is 5, gotj = 4
. - Swap (
i-1
,j
), got32415
. - Reverse the digits to the right of
i-1
, got32451
. - Check the length of the result. Return
None
if it’s not equal tonum.len()
.
fn next_smaller_number(n: u64) -> Option<u64> {
let mut digits: Vec<u64> = n.to_string().chars().map(|d| d.to_digit(10).unwrap() as u64).collect();
let mut i = digits.len() - 1;
while i > 0 && digits[i - 1] <= digits[i] { // find first digit that is smaller than the digit to its right
i -= 1;
}
if i == 0 {
return None;
}
let mut j = digits.len() - 1;
while digits[j] >= digits[i - 1] { // find the smallest digit to the right of i - 1 that is larger than it
j -= 1;
}
digits.swap(i - 1, j);
digits[i..].reverse();
let result = digits.iter().fold(0, |acc, &d| acc * 10 + d);
if result == 0 {
None
} else {
if result.to_string().len() != digits.len() {
return None;
}
Some(result)
}
}