• 下一个排列


    实际上就是c++中函数next_permutation的实现(包含重复元素)

    c++源码实现

    网址:https://en.cppreference.com/w/cpp/algorithm/next_permutation

    template<class BidirIt>
    bool next_permutation(BidirIt first, BidirIt last)
    {
        if (first == last) return false;
        BidirIt i = last;
        if (first == --i) return false;
     
        while (true) {
            BidirIt i1, i2;
     
            i1 = i;
            if (*--i < *i1) {
                i2 = last;
                while (!(*i < *--i2))
                    ;
                std::iter_swap(i, i2);
                std::reverse(i1, last);
                return true;
            }
            if (i == first) {
                std::reverse(first, last);
                return false;
            }
        }
    }
    
    
    

    思路

    两次从后扫描,第一次找较小数,第二次找较大数

    如何将一个数交换某两位位置让它变大,简单思考就是将左边的小数和右边的大数相交换就可以了。

    例如:12345将3和5互相交换可以得到12543,如何让12543比12543小但比12345大呢,可以将12543从5往后面的数进行升序即12534

    所以现在得到一个有用信息,交换后要将左边数位置之后的数进行升序。

    如何确定应该交换哪两个数可以得到较小的值?

    首先12345交换的两位越靠右得到的值比较小,例如交换1和5交换和4和5交换差的不是一点半点。

    所以两个数的搜索都应该从数组后面向前进行遍历查找,并且较小数越靠右越好。

    题解

    class Solution {
        public void nextPermutation(int[] nums) {
            int i = nums.length - 2;
            //找到较小数要靠右(从后面扫一遍)
            //找到较大数要尽可能小
            //交换较大数较小数,对较小数位置后面的数进行升序处理保证最小
            while(i >= 0 && nums[i] >= nums[i+1]){
                i--;
            }
            //[i+1,n]为降序
            if(i >= 0){
            int j = nums.length - 1;
            while(j >= 0 && nums[i] >= nums[j]){
                j--;
            }
            swap(i,j,nums);
            }
    
            reverse(i+1,nums.length-1,nums);
    
    
            
        }
        public void swap(int i,int j,int[] nums){
            int tmp  = nums[i];
            nums[i] = nums[j] ;
            nums[j] = tmp;
        }
        public void reverse(int start,int end,int[] nums){
            if(start >= end) return ;
            while(start < end){
                swap(start,end,nums);
                start++;
                end--;
            }
        }
    }
    
    
    
  • 相关阅读:
    [USACO4.2]草地排水Drainage Ditches
    bzoj3236:[AHOI2013]作业
    小A买彩票-(组合数)
    CSS样式整理大全
    P1880 [NOI1995]石子合并-(环形区间dp)
    P1147连续自然数和-(尺取法)
    POJ2456Aggressive cows-(二分判定)
    NYOJ737石子合并(二)-(区间dp)
    牛客网-乌龟跑步-(dfs)
    int和string之间的转换
  • 原文地址:https://www.cnblogs.com/cstdio1/p/13954113.html
Copyright © 2020-2023  润新知