[leetcode] 1503: Previous Permutation With One Swap

思路

1. 找到一个交换数A

如果input各个数位上的值是按数位递增的,可以判断不能交换出数值更小的permutation。

-> 反过来也就是说,如果input从右到左数位上的值全部是递减的就没有answer

-> 说明如果不满足这个条件就说明可以进行置换,从右到左找到第一个违反递减顺序的数A,需要用A与某一个数位交换

    可以证明:1) A右边的数组是降序的,内部交换不能得到更小的值;2) A左边的数值权重更大,用A左边的数去跟某个数位交换得到的smaller value一定会比用A交换更小。

    所以用A交换才能得到比input原数值更小的、数值最大的permutation。(又是更小又是最大什么鬼好难表达

2. 找到另一个交换数B

另一个交换数B一定是在A的右边、数值比A小的数。

因为:1) 如果A与左边的某个数C交换,要得到比input原值更小的数那么C一定比A大,在左边数位上降低数值影响的权重一定比在靠右数位上的大。

         2) A是第一个违反从右到左降序规律的元素,A右边一定存在比A数值更小的数。

又因为A右边是从右到左降序排列的,B应该是其中比A小的数中最靠右的。但还有一点要考虑,A右边并不是严格降序排列的,可能存在与B相邻且与B值相等的数D,这种情况下应选择这组相邻相等的数中最靠左的。因为B和D一定比A小,要交换A和其中一个数获得最大的小值数(什么鬼表达)应该要让A和其中最靠左的数交换,把大数值的A放在权重尽量高的位置上。

可以进一步推定B是在A右边、数值比A小的数中最靠右、如果有与其相等的相邻数则选其中最靠左(什么鬼真的好难表达

总结:从右到左找到首个违反降序规律的数A,找到A数值比A小的数中“最靠右、相等相邻数中最靠左”的数B,交换AB。如果找不到A说明没有可交换数位。

不会用数学语言证明我真的越来越垃圾了

code

class Solution {
public:
    vector<int> prevPermOpt1(vector<int>& A) {
        int N=A.size(), left;
        for (left=N-1;left>0;left--) {
            if (A[left-1]>A[left])
                break;
        }
        if (left==0)
            return A;
        --left;
        int right=N-1;
        while (A[right]>=A[left])
            --right;
        while (A[right]==A[right-1])
            --right;
        swap(A[left],A[right]);
        return A;
    }
};
原文地址:https://www.cnblogs.com/RDaneelOlivaw/p/10958704.html