zoukankan      html  css  js  c++  java
  • [LeetCode] 1053. Previous Permutation With One Swap

    Given an array of positive integers arr (not necessarily distinct), return the lexicographically largest permutation that is smaller than arr, that can be made with exactly one swap (A swap exchanges the positions of two numbers arr[i] and arr[j]). If it cannot be done, then return the same array.

    Example 1:

    Input: arr = [3,2,1]
    Output: [3,1,2]
    Explanation: Swapping 2 and 1.
    

    Example 2:

    Input: arr = [1,1,5]
    Output: [1,1,5]
    Explanation: This is already the smallest permutation.
    

    Example 3:

    Input: arr = [1,9,4,6,7]
    Output: [1,7,4,6,9]
    Explanation: Swapping 9 and 7.
    

    Example 4:

    Input: arr = [3,1,1,3]
    Output: [1,3,1,3]
    Explanation: Swapping 1 and 3.

    Constraints:

    • 1 <= arr.length <= 104
    • 1 <= arr[i] <= 104

    交换一次的先前排列。

    给你一个正整数的数组 A(其中的元素不一定完全不同),请你返回可在 一次交换(交换两数字 A[i] 和 A[j] 的位置)后得到的、按字典序排列小于 A 的最大可能排列。

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

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/previous-permutation-with-one-swap
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    这道题有两种思路,一种会利用到 treemap,一种是线性解法。这道题有点像在找下一个 permutation,但是这个 permutation 还不是下一个,而是比当前 input 给的 permutation 小的所有 permutation 里面最大的那个。

    这道题的核心在于无论是哪种做法,都必须是从右往左扫描 input 数组,从左往右是不行的。首先 treemap 的做法,对于当前的 input 数组给的 permutation,如果我们要找一个比他小的 permutation,我们首先需要找到一个下降的地方,比如第一个例子里的3 - 2,然后我们将 2 替换成比 2 小的数字里最大的那个(如果有的话)。按照这个例子就是 1。所以我们可以反过来思考,我们从右往左扫描,对于当前的数字,如果 treemap 里存在一个 lowerKey,那么就把当前数字和 lowerKey 进行 swap 即可。

    时间O(nlogn)

    空间O(n)

    Java实现

     1 class Solution {
     2     public int[] prevPermOpt1(int[] arr) {
     3         TreeMap<Integer, Integer> map = new TreeMap<>();
     4         int len = arr.length;
     5         map.put(arr[len - 1], len - 1);
     6         for (int i = arr.length - 2; i >= 0; i--) {
     7             Integer lower = map.lowerKey(arr[i]);
     8             if (lower != null) {
     9                 int j = map.get(lower);
    10                 swap(arr, i, j);
    11                 break;
    12             }
    13             map.put(arr[i], i);
    14         }
    15         return arr;
    16     }
    17 
    18     private void swap(int[] arr, int i, int j) {
    19         int temp = arr[i];
    20         arr[i] = arr[j];
    21         arr[j] = temp;
    22     }
    23 }

    再来是线性的解法。刚才 treemap 的解法是利用到 treemap 自动排序的特点。这里我们线性的解法则可以省去这个排序的步骤。还是从右往左扫描,按照题意我们需要找一个拐点。如果扫描下去一直是下坡的话(arr[i - 1] < arr[i]),则一直往下走;当我们找到一个拐点的时候,则停下,此时的 arr[i - 1] 是参与 swap 的元素之一。此时我们再次从右往左扫描,找到的第一个比 arr[i - 1] 小的元素是参与 swap 的另一个元素。把两者 swap 即可。

    时间O(n)

    空间O(1)

    Java实现

     1 class Solution {
     2     public int[] prevPermOpt1(int[] arr) {
     3         int len = arr.length;
     4         int a = len - 1;
     5         int b = len - 1;
     6         for (int i = len - 1; i >= 1; i--) {
     7             if (arr[i - 1] > arr[i]) {
     8                 a = i - 1;
     9                 break;
    10             }
    11         }
    12 
    13         for (int i = len - 1; i > a; i--) {
    14             if (arr[i] == arr[i - 1]) {
    15                 continue;
    16             }
    17             if (arr[i] < arr[a]) {
    18                 b = i;
    19                 break;
    20             }
    21         }
    22         swap(arr, a, b);
    23         return arr;
    24     }
    25 
    26     private void swap(int[] arr, int i, int j) {
    27         int temp = arr[i];
    28         arr[i] = arr[j];
    29         arr[j] = temp;
    30     }
    31 }

    LeetCode 题目总结

  • 相关阅读:
    java 正则表达式匹配指定变量并替换
    Tomcat 架构原理解析到架构设计借鉴
    优雅的缓存写法,以及synchronized 和 ReentrantLock性能 PK
    应用开发笔记|MYD-YA157-V2开发板CAN BUS 总线通信实例
    Arm Keil MDK V5.33版本更新,欢迎下载!
    Arm Development Studio 2020.1版本下载更新
    设计模式 | 享元模式(Flyweight)
    设计模式 | 中介者模式/调停者模式(Mediator)
    设计模式 | 职责链模式(Chain of responsibility)
    设计模式 | 命令模式(Command)
  • 原文地址:https://www.cnblogs.com/cnoodle/p/15150373.html
Copyright © 2011-2022 走看看