每日LeetCode —— 899. 有序队列

55 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

题目描述

       给定一个字符串s和整数k,你可以进行无限次操作,每次操作将字符串的前k个字符的其中一个字符移动到字符串末尾,给出所有可能的结果中字典序最小的字符串。

例1:输入:s="ccabd"  k=2  输出:"abccd"

解释:依次的变化顺序为"ccabd" -> "cabdc" -> "abdcc" -> "bdcca" -> "dccab" -> "dcabc" -> "dabcc" -> "abccd"。可以看出"abccd"是最小的字典序结果。

例2:输入:s="ccabd"  k=1  输出:"abdcc"

解释:依次的变化顺序为"ccabd" -> "cabdc" -> "abdcc"。

本题值得注意的地方

  • s由小写英文字母组成
  • k小于 s 的长度

原题地址:899. 有序队列

解题思路

       当 k=1k=1 时,每次只能将最开头的字符移动到结尾,所以我们可以很容易的看到,s经过变换最多有 s.lengths.length 种可能的情况,例如上面例二中k为1,则s的变换结果有5种,依次为 "ccabd"、 "cabdc" 、 "abdcc" 、 "bdcca" 、 "dccab"。

       当k不为1时,每次可以将前k个字符的其中之一移动到结尾,在这种情况下,因为我们操作的次数是不受限制的,所以s最终一定可以变为其最小的字典序(和将s排序的结果相同)。例如例1这种情况,我们已经知道s排序后的顺序为s1 = "abccd",那么我们如何才能将 s 变为 s1 呢。首先将s中的d移动到第一个位置,结果为"dabcc",然后根据s1判断d的前面为c,将c移动到d的后面一个位置,结果为"dccab",然后移动d、c至s1对应的位置"cabcd",此时可以看到,s的最后两个字符已经完成。接着根据s1可知cd前面的字符应该为c,将c移动到开始位置(此时已经在开始位置),然后将cd移动到c的后面"ccdab",接着将ccd移动到末尾"abccd"。此时已经为最小字典序。

       由上面的分析可以得到结论:

  • 当 k 为 1 ,结果为s.length种可能,直接返回这些可能中的最小的字典序即可。
  • 当 k 不为 1,则经过若干次移动操作后,s 必将可以变为对s进行排序后的结果。

实现代码


class Solution {
public:
    string orderlyQueue(string s, int k) {
        // 暂存s
        string res=s;
        if(k==1){
            // k 为 1,操作的结果最多有 s.length 种可能,找到其中最小字典序的结果
            for(int i=0;i<s.size();i++){
                char c = res[0];
                res.erase(0,1);
                res += c;
                s = s>res?res:s;
            }     
        }else{
            // 当 k > 1,最小字典序为对s进行排序后的结果
            sort(s.begin(),s.end());
        }
        return s;
    }
};