leetcode.1053 交换一次的先前排列 - 贪心 + 二分

1053. 交换一次的先前排列

题目:

给你一个正整数数组 arr(可能存在重复的元素),请你返回可在 一次交换(交换两数字 arr[i] 和 arr[j] 的位置)后得到的、按字典序排列小于 arr 的最大排列

如果无法这么操作,就请返回原数组

思路:

首先考虑【res的字典序小于arr】

  • 则我们需要找到arr[i]和arr[j],满足i<j(arr[i]在高位),且arr[i]>arr[j],这样两者交换后,res字典序则变小

其次考虑在满足上述条件情况下,满足【res是最大序列】

  • 则我们需要让变小的数位尽可能靠右(低位变小,整体变小的程度低),也就是让i尽可能大,则从后向前找i,找到第一个arr[i]>arr[i+1]的数
  • 与之交换的arr[j]即是在满足arr[i]<arr[j]的情况下最大的数,这样保证交换后变化程度最低
  • 特例:当遇到如[3,1,1,3]这种,arr[j]出现连续相同的情况,arr[j]应是更靠左端,因为arr[i]交换过来,在更高位时,保证目前最大序列
class Solution {
    public int[] prevPermOpt1(int[] arr) {
        int n=arr.length;
        /* 1、res的字典序<arr的字典序,设i<j,要满足交换前arr[i]>arr[j]
           2、res在1的基础上尽可能大:
                变小的位数靠右,也就是i尽可能大,从后向前找
                arr[j]在满足小于arr[i]的情况下尽可能大,用一个小于等于arr[i]的最大数替代,保证最大序列 
        */
        for(int i=n-2;i>=0;i--)
            if(arr[i]>arr[i+1])
            {
                int x=arr[i];
                int l=i+1,r=n-1;
                //在arr[i]后,找到不大于x的最大值
                while(l<r)
                {
                    int mid=l+r>>1;
                    if(arr[mid]>=x) r=mid;
                    else l=mid+1;
                }
                if(arr[i]<=arr[r]) r--; 
                while(arr[r]==arr[r-1]) r--; //像[3,1,1,3]在位数相等时取高位,这样可使arr[i]在较高的位数,保证最大序列
                //System.out.print(i+" "+l);
                int t=arr[i];
                arr[i]=arr[r];
                arr[r]=t;
                break;
            }
        return arr;
    }
}
class Solution {
    public int[] prevPermOpt1(int[] arr) {
        int n=arr.length;
        /* 1、res的字典序<arr的字典序,设i<j,要满足交换前arr[i]>arr[j]
           2、res在1的基础上尽可能大:
                变小的位数靠右,也就是i尽可能大,从后向前找
                arr[j]在满足小于arr[i]的情况下尽可能大,用一个小于等于arr[i]的最大数替代,保证最大序列 
                如果arr[j]出现连续相同的情况,则选位数更高位的,这样能将换过来的arr[i]放置在较高位,保证最大序列
        */
        for(int i=n-2;i>=0;i--)
            if(arr[i]>arr[i+1])
            {
                for(int j=n-1;j>i;j--)
                    if(arr[j]<arr[i]&&arr[j]!=arr[j-1])
                    {
                        int t=arr[i];
                        arr[i]=arr[j];
                        arr[j]=t;
                        return arr;
                    }
            }
        return arr;
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_61639349/article/details/129931421