我正在尝试编写一个带正整数的函数,并返回包含相同数字的下一个较小的正整数,并且当没有包含相同数字的较小数字时返回-1。
For example:
nextSmaller(21) == 12
nextSmaller(531) == 513
nextSmaller(2071) == 2017
我编写了一个解决此问题的代码,但我真的不知道如何进一步优化它。请你帮助我好吗?它在repl.it上运行得相当快,但是当我提交它时,它表示它需要超过1200毫秒并且不允许我提交它,即使所有测试都通过了。
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;
}
}
答案 0 :(得分:3)
你的代码可以稍微优化一下,例如你可以在你的内循环中使用break语句,一旦你知道当前的一个不起作用(它应该让它运行)就转移到下一个数字在大约一半的时间内,但n
91234567
并且在循环中代替n.toString().split("").length
仍然相当慢,请使用变量,因此您只需要将n转换为数组一次。
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;
}
有一种非常有效的计算下一个排列的算法,可以很容易地调整以获得前一个排列(如果结果排列以0
开始,则返回-1)。我改编this algorithm来做到这一点:
[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('');
}
答案 1 :(得分:2)
算法可能如下所示:
对于输入数字n
,查找由permutations
和same digits
这些数字sort
形成的所有数字。例如,如果n=213
,我们将排序列表作为[123, 132, 213, 231, 312, 321]
。 (例如,Permutations in JavaScript?可以帮助您)。
在排序列表中查找数字index i
的{{1}}。如果n
返回i>0
处的号码,则返回index i-1
(如果它是排序列表第一个位置出现的最小数字)。
另一种替代算法可能如下:
减去数字-1
直到除非您找到一个具有完全相同的数字(以不同的顺序,您可以对数字进行排序并检查相等性)。
效率最高的将类似于@Paulpro(https://www.nayuki.io/page/next-lexicographical-permutation-algorithm)提到的那个
n
的十进制字符串表示中找到longest non-decreasing suffix
。n
不递减,则返回-1(不能有任何小字符串)。n
,并将其与pivot
中的the leftmost
和the largest
数字交换为{suffix
1}}比smaller
。退回这个号码。