算法笔记17:下一个更大元素 III

251 阅读1分钟

556.下一个更大元素 III

暴力算法不用看了肯定超时。而线性复杂度解法的核心思想在于:对于一个数字的集合,其能形成的最大数字一定是按照降序进行排列组成,反之最小的数字一定是按照升序排列组成。

这个题目的特殊之处在于要找到邻近的下一个更大元素。所以第一步是要先找到从哪里开始,就是下一个了。以数字 3744951 为例,我们可以发现后三位 951 符合降序的规则,所以说明改变这三位的顺序是无意义的,不可能找到比 951 更大的数字了。那么再前进一位去看是 4 。那么 (4, 9, 5, 1) 这个集合里面,4951 这个数字显然就不是最大的了。可怎么找到下一个更大的数呢?

只需要把 4 和后面几个数里比 4 大的那些里最小的数放到 4 所在的位置就行了。95 是比 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;
};