求一个数字用其相同数字重新组合后下一个大的数字

比如63543,这个数包含6,3,5,4,3,将这些数字重新组合以后,产生下一个较大的数字,那么就是64335。


这个问题在career cup上看到的,网上没有解答。想了一个办法,应该是没问题的。


其实题目的描述就已经给出了一个解法,就是穷举法。比如输入数字为n,将这个数字每个位上的数字求出来,存在一个数组里,然后产生它的所有排列。那么时间复杂度就是O(n!)。空间复杂度为O(log_10 n)。


下面介绍一种较好的求解方法。


观察这个数字63543,求出第一个逆序对,也就是63543。如果直接交换这两个逆序对,然后将剩下的数字升序排序,产生65334,不是所求。观察发现,如果用第一个逆序数字3与之前的有序数字中的4交换,得到64533,然后再升序排序一下之前的有序部分,得到64335,既为所求。


以下是Java实现:

import java.util.Stack;
import java.util.Random;
public class NextHigher {
  public static void swap(int[] a, int m, int n) {
    if (a[m] != a[n]) {
      a[m] ^= a[n];
      a[n] ^= a[m];
      a[m] ^= a[n];
    }
  }

  public static int partition(int[] a, int l, int h) {
    int i = l - 1;
    int pivot = a[h];
    for (int j = l; j <= h; j++) {
      if (a[j] < pivot) {
        i++;
        swap(a, i, j);
      }
    }
    swap(a, i + 1, h);
    return i + 1;
  }

  public static void quickSort(int[] a, int l, int h) {
    if (l < h) {
      int p = partition(a, l, h);
      quickSort(a, l, p - 1);
      quickSort(a, p + 1, h);
    }
  }
  
  public static void findNextHigher(int[] a) {
    if (a.length == 1) {
      System.out.println("No next higher number");
      return;
    }
    int i = a.length - 1;
    for (i = a.length - 1; i >= 0; i--) {
      if (i < a.length - 1 && a[i] < a[i + 1]) {
        break;
      }
    }

    if (i < 0) {
      System.out.println("No next higher number");
      return;
    }

    int diff = Integer.MAX_VALUE;
    int idx = 0;
    for (int j = i + 1; j < a.length; j++) {
      if (a[j] - a[i] > 0 && a[j] - a[i] < diff) {
        diff = a[j] - a[i];
        idx = j;
      }
    }
    
    swap(a, idx, i);
    quickSort(a, i + 1, a.length - 1);
    for (int e : a) {
      System.out.print(e);
    }
    System.out.println();
  }
  public static int[] numToArray(int i) {
    Stack<Integer> s = new Stack<Integer>();
    do {
      s.push(i % 10);
      i = i / 10;
    } while (i != 0);
    int[] rtn = new int[s.size()];
    i = 0;
    for (i = 0; i < rtn.length; i++) {
      rtn[i] = s.pop();
    }
    return rtn;
  }
  
  public static void main(String[] args) {
    Random rnd = new Random();
    System.out.println("Boundary case: 0 ");
    findNextHigher(numToArray(0));
    System.out.println("Boundary case: 5 ");
    findNextHigher(numToArray(5));
    System.out.println("Boundary case: 10 ");
    findNextHigher(numToArray(10));
    System.out.println("Boundary case: 321 ");
    findNextHigher(numToArray(321));
    for (int i = 0; i < 10; i++) {
      int num = rnd.nextInt() & 0x7fffffff;
      System.out.println(num);
      findNextHigher(numToArray(num));
    }
  }
}


你可能感兴趣的:(求一个数字用其相同数字重新组合后下一个大的数字)