Construct Smallest Number From DI String
Construct Smallest Number From DI String
You are given a 0-indexed string pattern of length n consisting of the characters 'I' meaning increasing and 'D' meaning decreasing.
A 0-indexed string num of length n + 1 is created using the following conditions:
- num consists of the digits '1' to '9' , where each digit is used at most once.
- If pattern[i] == 'I' , then num[i] < num[i + 1] .
- If pattern[i] == 'D' , then num[i] > num[i + 1] .
Return the lexicographically smallest possible string num that meets the conditions.
Example 1:
Input: pattern = "IIIDIDDD" Output: "123549876" Explanation: At indices 0, 1, 2, and 4 we must have that num[i] < num[i+1]. At indices 3, 5, 6, and 7 we must have that num[i] > num[i+1]. Some possible values of num are "245639871", "135749862", and "123849765". It can be proven that "123549876" is the smallest possible num that meets the conditions. Note that "123414321" is not possible because the digit '1' is used more than once.
Example 2:
1 Input: pattern = "DDD" 2 Output: "4321" 3 Explanation: 4 Some possible values of num are "9876", "7321", and "8742". 5 It can be proven that "4321" is the smallest possible num that meets the conditions.
Constraints:
pattern consists of only the letters 'I' and 'D' .
解题思路
可以发现方案数很少,只有个,因此可以直接枚举全排列,找到合法的字典序最小的输出就可以了,因此可以直接从字典序最小的全排列进行枚举。
AC代码如下,计算量最大为:
1 class Solution { 2 public: 3 string smallestNumber(string str) { 4 int n = str.size(); 5 string ret; 6 for (int i = 1; i <= n + 1; i++) { 7 ret += (char)(i + '0'); 8 } 9 10 do { 11 bool flag = true; 12 for (int i = 0; i < n; i++) { 13 if (str[i] == 'I' && ret[i] > ret[i + 1]) { 14 flag = false; 15 break; 16 } 17 if (str[i] == 'D' && ret[i] < ret[i + 1]) { 18 flag = false; 19 break; 20 } 21 } 22 if (flag) break; 23 } while (next_permutation(ret.begin(), ret.end())); 24 25 return ret; 26 } 27 };
还有一种贪心解法,时间复杂度为。根据样例模拟可以发现,我们可以根据这种组合形式将字符串分成若干组,每一组前部分均为,后部分均为(不一定有)。每一组中的数都是先递增再递减。为了保证字典序最小,每一组中最小的数就是前一组中最大的数加(第组数的最小数为),说白了前面有多少个数那么当前就从下一个数开始选。
一开始先构造出答案序列,然后扫描每一个组合,其中如果是则继续往后枚举,直到遇到,接着往后找到所有连续的一段。假设序列的起始位置为,序列最后一位的下标为,那么就把答案序列的位进行翻转,以此类推。
AC代码如下:
1 class Solution { 2 public: 3 string smallestNumber(string str) { 4 int n = str.size(); 5 string ret; 6 for (int i = 1; i <= n + 1; i++) { 7 ret += (char)(i + '0'); 8 } 9 10 for (int i = 0; i < n; i++) { 11 if (str[i] == 'D') { 12 int j = i + 1; 13 while (j < n && str[j] == 'D') { 14 j++; 15 } 16 reverse(ret.begin() + i, ret.begin() + j + 1); 17 i = j - 1; 18 } 19 } 20 21 return ret; 22 } 23 };
参考资料
y总,比赛遇到原题了怎么办?力扣第306场周赛:https://www.bilibili.com/video/BV1wv4y1c71n
【力扣周赛 306】数位 DP 通用模板 | LeetCode 算法刷题:https://www.bilibili.com/video/BV1rS4y1s721
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/16588895.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效