暴力算法不用看了肯定超时。而线性复杂度解法的核心思想在于:对于一个数字的集合,其能形成的最大数字一定是按照降序进行排列组成,反之最小的数字一定是按照升序排列组成。
这个题目的特殊之处在于要找到邻近的下一个更大元素。所以第一步是要先找到从哪里开始,就是下一个了。以数字 3744951 为例,我们可以发现后三位 951 符合降序的规则,所以说明改变这三位的顺序是无意义的,不可能找到比 951 更大的数字了。那么再前进一位去看是 4 。那么 (4, 9, 5, 1) 这个集合里面,4951 这个数字显然就不是最大的了。可怎么找到下一个更大的数呢?
只需要把 4 和后面几个数里比 4 大的那些里最小的数放到 4 所在的位置就行了。9 和 5 是比 4 大的,但是如果放 9 的话就比 4951 大太多了,显然应该是放 5。
那么剩下的任务就比较直接了,接下来我们就只需要找出来 (4, 9, 1) 组成的数字里最小的是那个。显然是 149 ,其实就是把剩下的数字反转一下就行了,因为之前我们已经确认过这个集合是降序排列了。
代码如下:
const nextGreaterElement = (n) => {
const strArr = n.toString().split('');
let i = strArr.length - 2;
for (; i >= 0; i--) {
if (strArr[i] < strArr[i + 1]) {
break;
}
}
if (i < 0) {
return -1;
}
let j = strArr.length - 1;
while(j >= 0 && strArr[j] <= strArr[i]) {
j--;
}
const t = strArr[i];
strArr[i] = strArr[j];
strArr[j] = t;
let p = i + 1;
let q = strArr.length - 1;
while(p < q) {
const t = strArr[p];
strArr[p] = strArr[q];
strArr[q] = t;
p++;
q--;
}
const res = parseInt(strArr.join(''));
return res >= 2 ** 31 ? -1 : res;
};