一道算法题(next smaller)

问题以下:

给定某一个正整数,构成这个数的数字稳定,返回下一个比它小的数,如:

nextSmaller(21) == 12
nextSmaller(531) == 513
nextSmaller(907) == 790
nextSmaller(51226262651257) == 51226262627551

假如没有下一个比它小的数字,或许下一个比它小的数字以0开首,则返回-1,如:

nextSmaller(9) == -1
nextSmaller(111) == -1
nextSmaller(135) == -1
nextSmaller(1027) == -1 // 0721以0开首,所以返回-1

算法形貌(找到下一个比它小的数):

1.find pivot:这个数从右往左,一名位地来比较,假如第i位的数字,比第i+1位的数字大,则把第i位的数字置为pivot(标志位)。
2.swap:从pivot位向右,找到比pivot小的最大的那个数,并与pivot交流。
3.sort:交流后,把pivot位向右(注重是pivot的index,不是pivot的值)的一切数字降序分列。
如许,新获得的数就是下一个比它小的数。

举例剖析:

比方我们拿54123来剖析。
1.find pivot:从最右侧的3来看,由于3没有第i+1位数字(3没有右侧),所以左移一名到2;2比右侧的3小,所以继承左移一名到1;同理,1也比2要小,所以继承左移一名到4;4比1要大了,那末把4置为pivot,这时候住手。
2.swap:如今4是pivot,那末从4向右,有1,2,3三个数字,而且都比4小,这个中3是最大的,所以把4和3的位置交流,获得53124。
3.sort:交流后,pivot位上是3,把3往右的一切数字降序分列,获得53421,这就是下一个比54123小的数。

为何如许做?

下面是我本身思索的为何,不一定对。

关于每个数,它最小的分列只要1种状况,就是权位从高到低,数字从小到大分列。
比方123的最小分列就是123。
关于54123来讲,从右向左能够支解为3,23,123,这三种状况都是最小分列。
也就是说,假如我们只对3或许23或许123举行重组,是没有变化的。
因而再向左举行支解,获得5和4123,发明4123已不再是最小分列了,换句话说4123一定有下一个比它小的数,就把4标记出来,对4123举行重组。
怎样重组呢?最高的权位,放上比4稍小的,也就是3,然后关于3xxx的后三位,放上值最大的状况,就是412的降序分列421,如许就可以保证“3421是4123的上一个数”。

总结:

这个算法一句话总结:关于某个数,从右向左找它的子列,假如子列是最小分列,那子列没法重组,继承向右;假如子列不是最小分列,就对子列举行重组。

觉得算法里,“分治”加“pivot(标志位)”的解法很经常使用啊,把复杂状况分红最简朴的子状况,假如符合规律,那末子状况扩大,假如不符合规律,那末置上标志位,再举行斟酌。

下面是写得不怎样样的代码:

function nextSmaller(num) {
  var arr = [];
  (num + "").split("").forEach(function (val) {
    arr.push(parseInt(val));
  });
  // 1st: find the pivot, if digit is greater than its right digit, it becomes a pivot
  var pivot = -1;
  for(var i = arr.length - 2; i >= 0;i--) {
    if (arr[i] > arr[i + 1]) {
      pivot = i;
      break;
    }
    if (i == 0) {
      return -1;
    }
  }
  // 2nd: find the least less than the pivot, and swap them
  var swap = -1;
  for (i = pivot + 1;i < arr.length;i++) {
    if (swap < 0) {
      if (arr[i] < arr[pivot]) {
        swap = i;
      }
    } else {
      if (arr[i] < arr[pivot] && arr[i] > arr[swap]) {
        swap = i
      }
    }
  }
  var _mem;
  _mem = arr[pivot];
  arr[pivot] = arr[swap];
  arr[swap] = _mem;
  if (arr[0] == 0) {
    return -1;
  }
  // 3rd: sort the right of pivot, decreasingly
  var firstArray = arr.slice(0, pivot + 1);
  var secondArray = arr.slice(pivot + 1);
  secondArray.sort(function (a, b) {
    return b -a;
  });
  // 4th: return val
  var result = (firstArray.concat(secondArray)).join("");
  if (result == num){
    return - 1
  }
  return parseInt(result);
}
    原文作者:隐约雷鸣
    原文地址: https://segmentfault.com/a/1190000008049332
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞