I am trying to write a function that takes a positive integer and returns the next smaller positive integer containing the same digits, and -1 when there is no smaller number that contains the same digits.
For example:
nextSmaller(21) == 12
nextSmaller(531) == 513
nextSmaller(2071) == 2017
I wrote a code that solves this, but I don't really know how to optimize it further. Could you please help me? It runs fairly fast on repl.it, but when I submit it, it says it takes more than 1200ms and doesn't allow me to submit it even though all the tests pass.
function nextSmaller(n) {
var nArray= n.toString().split("")
var minimumNum = 1 + Array(nArray.length).join('0')
for(var i=n-1; i >= minimumNum; i--) {
var newNumArray = i.toString().split('');
var counter = 0;
for (var j=0; j<newNumArray.length; j++) {
if (nArray.indexOf(newNumArray[j]) > -1) {
counter++
nArray.splice(nArray.indexOf(newNumArray[j]), 1)
if (counter === n.toString().split("").length) {
return i;
}
}
}
nArray = n.toString().split("");
if (i === Number(minimumNum)) return -1;
}
}
Python: Function that takes a positive integer and returns the sum of the cube of all the positive integers smaller than the specified number - w3resource. w3resource.
my_function <- function ( x) { # Create function x ^3 + 2 * x ^2 - 10 * x } Now, we can apply the optimize () command to optimize our user-defined function. In this example, we are using a lower interval limit of -1 and an upper interval limit of 1.
Also return -1 when the next smaller number with the same digits would require the leading digit to be zero. nextSmaller ( 9) == -1 nextSmaller ( 111) == -1 nextSmaller ( 135) == -1 nextSmaller ( 1027) == -1 // 0721 is out since we don't write numbers with leading zeros
Let’s dig in… Definition: The optimize R function performs one dimensional optimization. Basic R Syntax: You can find the basic R programming syntax of the optimize function below. In the following, I’ll show an example for the application of the optimize function in R programming.
Your code could be optimized a bit, for instance you could use a break statement in your inner loop to move on to the next number as soon as you know the current one isn't going to work (that should make it run in about half the time, but it is still quite slow for an n
like 91234567
) and instead of n.toString().split("").length
in the loop, use a variable so you only need to convert n to an array once.
function nextSmaller(n) {
var nArray = n.toString().split("")
var length = nArray.length;
var minimumNum = 1 + Array(length).join('0')
for(var i=n-1; i >= minimumNum; i--) {
var newNumArray = i.toString().split('');
var counter = 0;
for (var j=0; j<newNumArray.length; j++) {
if (nArray.indexOf(newNumArray[j]) < 0)
break;
counter++
nArray.splice(nArray.indexOf(newNumArray[j]), 1)
if (counter === length) {
return i;
}
}
nArray = n.toString().split("");
}
return -1;
}
There is a very efficient algorithm for computing the next permutation, which can easily be adapted to get the previous one instead (and return -1 if the resulting permutation starts with 0
). I adapted this algorithm to do that:
[21,531,2071,912345678,9123545678,915345678].forEach( x => console.log( nextSmaller( x ) ) );
function nextSmaller(n) {
const arr = ( n + '' ).split( '' ).map( Number );
// Find longest non-decreasing suffix
let i, prev = 9;
for ( i = arr.length; i--; ) {
if ( arr[ i ] > prev )
break;
prev = arr[ i ];
}
// If whole sequence is non-decreasing,
// it is already the smallest permutation
if ( i < 0 )
return -1;
const pivot_i = i;
const pivot = arr[ pivot_i ];
for ( i = arr.length; i--; ) {
if ( arr[ i ] < pivot )
break;
}
arr[ pivot_i ] = arr[ i ];
arr[ i ] = pivot;
if ( arr[ 0 ] === 0 )
return -1;
return +arr.slice( 0, pivot_i + 1 ).concat( arr.slice( pivot_i + 1 ).reverse( ) ).join('');
}
The algorithm could be like the following:
For the input number n
find all numbers that are formed with some permutations
of the same digits
and sort
these numbers. For example, if n=213
, we get the sorted list as [123, 132, 213, 231, 312, 321]
. (e.g., Permutations in JavaScript? can help you).
Find the index i
of the number n
in the sorted list. If i>0
return the number at index i-1
else return -1
(if it's the smallest number appearing at the first position of the sorted list).
Another alternative algorithm could be the following:
Decrement the number n
until and unless you find one that has exactly same digits (in a different order, you can sort the digits and check for equality).
The most efficient will be similar to the one referred to by @Paulpro(https://www.nayuki.io/page/next-lexicographical-permutation-algorithm)
longest non-decreasing suffix
from the decimal string representation of n
.n
is non-decreasing then return -1 (there can't be any smaller).pivot
and swap it with (the leftmost
and) the largest
digit in the suffix
that is smaller
than the pivot
. Return this number.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With