【C/C++】942. 增减字符串匹配

126 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第9天,点击查看活动详情


题目链接:942. 增减字符串匹配

题目描述

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

  • 如果 perm[i] < perm[i + 1] ,那么 s[i] == 'I' 
  • 如果 perm[i] > perm[i + 1] ,那么 s[i] == 'D'  给定一个字符串 s ,重构排列 perm 并返回它。如果有多个有效排列 perm,则返回其中 任何一个

提示:

  • 1s.length1051 \leqslant s.length \leqslant 10^5
  • s 只包含字符 "I" 或 "D"

示例 1:

输入:s = "IDID"
输出:[0,4,1,3,2]

示例 2:

输入:s = "III"
输出:[0,1,2,3]

示例 3:

输入:s = "DDI"
输出:[3,2,0,1]

整理题意

题目给定了一个字符串 ss 只包含字符 'I' 或 'D'

  • 字符 'I' 表示增加,也就是 perm[i] < perm[i + 1]
  • 字符 'D' 表示减少,也就是 perm[i] > perm[i + 1]; 让我们根据字符串 s 构造由 [0, n] 内所有整数组成的 n + 1 个整数的排列序列 perm ,返回满足条件的 任何一个

根据 示例1 得下图: 增减字符串.jpg 字符串 s 反应增减,我们需要根据字符串 s 来构造一个满足题目要求的排列序列 perm

当然 [0, 3, 1, 4, 2] 也是可行的答案。

解题思路分析

由于返回任何一个满足条件的答案即可,我们可以尝试考虑 贪心 构造:

  • s[i] == 'I' 时,令当前位置 perm[i][0, n] 内剩余数字中最小的数字,这样可以使得无论后面一位在其余数字中选择任意数字都可以使得 perm[i] < perm[i + 1]
  • s[i] == 'D' 时,令当前位置 perm[i][0, n] 内剩余数字中最大的数字,这样可以使得无论后面一位在其余数字中选择任意数字都可以使得 perm[i] > perm[i + 1]
  • 如此循环直至剩余最后一位时放入最后剩余的那一个数即可。

具体实现

由于每次选取 [0, n] 内剩余数字中最小或最大的数字,我们这里可以使用两个变量记录当前剩余数字中最大值和最小值即可,具体操作:

  1. 遍历字符串 s
  2. 根据字符串 s[i] 的字符情况来更新答案数组 ans[i]
  3. 最后一位 ans[n] 放入最后剩余的那个数字即可,此时最大值等于最小值,放入最大值或最小值都可。

复杂度分析

  • 时间复杂度:O(n)O(n),其中 n 是字符串 s 的长度,仅需遍历一次字符串即可。
  • 空间复杂度:O(1)O(1),返回值不计入空间复杂度。

代码实现

class Solution {
public:
    vector<int> diStringMatch(string s) {
        int n = s.length();
        vector<int> ans(n + 1);
        //pre 记录最小值,sub 记录最大值
        int pre = 0, sub = n;
        //遍历字符串s
        for(int i = 0; i < n; i++){
            //每次根据s[i]来判断选取pre还是sub
            ans[i] = s[i] == 'I' ? pre++ : sub--;
        }
        //ans[n] 为剩余的最后一个数字即此时 pre = sub
        ans[n] = pre;
        return ans;
    }
};

总结

  • 该题核心思想在于 贪心 构造,考虑当前位置放置什么数字不影响后面的放置。
  • 需要注意的细节是字符串 s 长度比最后返回的答案数组 ans 要少一位,此时最后一位放置的数字正好是 [0, n] 中剩下的最后一位。

结束语

不知道自己想做什么,就先把手头的事做好;不知道自己会遇到谁,就先学会善待身边的人;不知道现在做的有没有意义,至少先确定自己不是什么都没做。生活的迷雾里你或许只能看见眼前的五米,但一步一步走下来,雾就会慢慢散去。