讀書筆記——漫畫算法(6) 尋找全排列的下一個數

尋找全排列的下一個數,這題的意思就是:

給出一個數,求出由每位數形成的所有全排列中,大於此數的最小值


注:我們給出的這個數每位都不同

具體的算法描述如下:

/**
* 
* 1. 從後向前尋找逆序區域,並返回逆序區域的最左側索引
* 2. 將nums[index-1]與nums區間[index, nums.length-1]中大於nums[index-1]的最小元素進行位置交換
* 3. 將數組nums區間[index, nums.length-1]逆序
*
* 舉個例子:12354
* 1. 找到逆序區域123|54| ,最左側索引index = 3
* 2. 將3與4進行交換,得到124|53這樣保證最高位能夠最小
* 3. 將逆序區間順序得到:124|35
*/

算法實現如下:
首先定義一個抽象類,方便表示整個算法的流程:

public abstract class TemplateFindNearestNumber {

    protected int[] arr;

    private TemplateFindNearestNumber() {  }

    TemplateFindNearestNumber(int[] arr) {
        Objects.requireNonNull(arr);
        this.arr = arr;
    }

    /**
     * 1. 從後向前尋找逆序區域,並返回逆序區域的最左側索引
     * 2. 將nums[index-1]與nums區間[index, nums.length-1]中大於nums[index-1]的最小元素進行位置交換
     * 3. 將數組nums區間[index, nums.length-1]逆序
     * @return
     */
    public int[] findNearestNumber() {
        int index = findReversedOrderBorderIndex(arr);
        if(index == 0) {
            return null;
        }
        int[] copyNums = Arrays.copyOf(arr, arr.length);
        exchangeHead(copyNums, index);
        reverse(copyNums, index);
        return copyNums;
    }

    /**
     * 從後向前尋找逆序區域,並返回逆序區域的最左側索引
     * @param nums
     * @return
     */
    protected abstract int findReversedOrderBorderIndex(int[] nums);

    /**
     * 將nums[index-1]與nums區間[index, nums.length-1]中
     * 大於nums[index-1]的最小元素進行位置交換
     * @param nums
     * @param index
     */
    protected abstract void exchangeHead(int[] nums, int index);

    /**
     * 將數組nums區間[index, nums.length-1]逆序
     * @param nums
     * @param index
     */
    protected abstract void reverse(int[] nums, int index);
}

再定義核心的算法實現,其中最後的main函數,對整個算法進行測試

public class FindNearestNumber extends TemplateFindNearestNumber {

    public FindNearestNumber(int[] arr) {
        super(arr);
    }

    @Override
    public int findReversedOrderBorderIndex(int[] nums) {
        int index = nums.length-1;
        while(index > 0 && nums[index-1] >= nums[index]) {
            index--;
        }
        return index;
    }

    @Override
    protected void exchangeHead(int[] nums, int index) {
        int num = nums[index-1];
        for(int i = nums.length-1 ; i >= index ; i--) {
            if(nums[i] > num) {
                swap(nums, index-1, i);
                break;
            }
        }
    }

    @Override
    protected void reverse(int[] nums, int index) {
        int t = nums.length - 1;
        while(index < t) {
            swap(nums, index++, t--);
        }
    }

    private void swap(int[] arr, int i, int j) {
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4, 5 };
        TemplateFindNearestNumber solution = null;
        for(int i = 0 ; i < 10 ; i++) {
            solution = new FindNearestNumber(arr);
            arr = solution.findNearestNumber();
            System.out.println(Arrays.toString(arr));
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章