leetcode 484,s[i] == 'I',s[i] == 'D'重构字典序最小排列

421 阅读3分钟

题目描述

由范围[1,n]内所有整数组成的n个整数的排列perm可以表示为长度n-1的字符串s,其中:

  • 如果perm[i] < perm[i+1],那么s[i] == 'I'
  • 如果perm[i] > perm[i+1],那么s[i] == 'D'

给定一个字符串s,重构字典序上最小的排列perm并返回它。

示例1:

输入:s = “I”
输出:[1,2]
解释:[1,2] 是唯一合法的可以生成密钥签名“I”的特定串,数字 12 构成递增关系。

示例2:

输入:s = “DI”
输出:[2,1,3]
解释:[2,1,3][3,1,2] 可以生成密钥签名 "DI"。
但由于我们要找字典序最小的排列,因此你需要输出[2,1,3]

示例3:

输入:s = “DDIII”
输出:[3, 2, 1, 4, 5, 6]

提示:

  • 1 <= s.length <= 10^5
  • s[i]只包含字符“D”和“I”

分析思路

小窍门:从数据范围看,1w的数据范围,如果平方一定会超时,要考虑nlogn的实现,这里考虑单调栈。

通过分析可以发现,答案长度输入s的长度+1

如何字典序最小?只要数据是有顺序(从小到大)的取数据,来从左往右生成答案,就是最小的排列,按照这个思路。

把有序整数数组的arr[i],依次添加到栈里边,直到出现变化。

什么情况下变化,变化了什么?出现拐点,一般就是低谷,或者山峰。

变化了怎么办?根据题意的判定条件,对存在栈内的元素,正确的转移到答案内,或者正确的排序栈内元素的位置。

这里答案,用新的数组来存储。

贪心的思考,我一开始定义为,都是‘D’,那么我把 每一个 arr[i],放进去 stack,如果一直是‘D’,那么就持续的放进去,最终反转一下,就是满足递减顺序的最小排列。

  • 如果 遇到 “I”,当前的 arr[i],也是大于堆顶元素的,直接入栈。但是要考虑下当前元素和栈内元素的关系。

  • 这个arr[i],会参与到之前位置和前前的“DI”关系吗,并不会。它就属于这个位置了,不参与,就不要整体和之前的放到一个栈内。那么就把之前的栈内元素清空到答案内。所以遇到 ‘I’时,要把之前的反转,并且出栈到答案内。并且也把当前的这个转移到答案内。

  • 如果 遍历到n,栈内还有元素,说明栈内元素都是递减顺序的,需要反转到答案内。

代码实现

public int[] findPermutation(String s) {
    ArrayDeque<Integer> stack = new ArrayDeque<>();
    int n = s.length() + 1;
    int[] ans = new int[n];
    int idx = 0;

    for (int i = 1; i <= n; i++) {
        stack.addLast(i);
        if (i == n || s.charAt(i - 1) == 'I') {
            while (!stack.isEmpty()) {
                ans[idx++] = stack.pollLast();
            }
        }
    }
    return ans;
}

输出 [3, 2, 1, 4, 5, 6]

WechatIMG157.jpg

纠结误区

以下是错误的想法

我只判断当前i位置元素栈顶元素的大小关系,进行反转,这样会造成反转后的结果影响已有的大小关系。要考虑连续性的问题。所以循环判断,并且及时出栈

public int[] findPermutation(String s) {
    ArrayDeque<Integer> stack = new ArrayDeque<>();
    int n = s.length() + 1;
    int[] ans = new int[n];
    if (s == null || s.length() ==0 ) return ans;
    int[] nums = new int[n];
    for (int i = 0; i < n; i++) {
        nums[i] = i + 1;
    }
    stack.addLast(nums[0]);
    char[] chars = s.toCharArray();
    int idx = 1;
    for (char ch : chars) {
        if (ch == 'I') {
            stack.addLast(nums[idx]);
        } else if (ch == 'D') {
            int pop = stack.pollLast();
            stack.addLast(nums[idx]);
            stack.addLast(pop);
        } else {
            return ans;
        }
        idx++;
    }
    int i = 0;
    for (Integer v : stack) {
        ans[i++] = v;
    }
    return ans;
}

输出 [2, 3, 1, 4, 5, 6]