根据模式串构造最小数字

简介: 根据模式串构造最小数字

说在前面

🎈不知道大家对于算法的学习是一个怎样的心态呢?为了面试还是因为兴趣?不管是出于什么原因,算法学习需要持续保持。

题目描述

给你下标从 0 开始、长度为 n 的字符串 pattern ,它包含两种字符,'I' 表示 上升'D' 表示 下降

你需要构造一个下标从 0 开始长度为 n + 1 的字符串,且它要满足以下条件:

  • num 包含数字 '1''9' ,其中每个数字 至多 使用一次。
  • 如果 pattern[i] == 'I' ,那么 num[i] < num[i + 1]
  • 如果 pattern[i] == 'D' ,那么 num[i] > num[i + 1]

请你返回满足上述条件字典序 最小 的字符串 **num

示例 1:

输入: pattern = "IIIDIDDD"
输出: "123549876"
解释: 下标 0 ,1 ,2 和 4 处,我们需要使 num[i] < num[i+1] 。
下标 3 ,5 ,6 和 7 处,我们需要使 num[i] > num[i+1] 。
一些可能的 num 的值为 "245639871" ,"135749862" 和 "123849765" 。
"123549876" 是满足条件最小的数字。
注意,"123414321" 不是可行解因为数字 '1' 使用次数超过 1 次。

示例 2:

输入: pattern = "DDD"
输出: "4321"
解释:
一些可能的 num 的值为 "9876" ,"7321" 和 "8742" 。
"4321" 是满足条件最小的数字。

提示:

  • 1 <= pattern.length <= 8
  • pattern 只包含字符 'I''D'

思路分析

首先我们还是要先来理解一下题意,题目会给出一串只包含ID两种字符的字符串,其中'I' 表示 上升,即如果 pattern[i] == 'I' ,那么 num[i] < num[i + 1]'D' 表示 下降,即如果 pattern[i] == 'D' ,那么 num[i] > num[i + 1] 。我们需要构造一个下标从 0 开始长度为 n + 1 的字符串,字符串应该满足题目给出参数的升降规则,而且是满足上述条件字典序 最小 的字符串 num

暴力搜索

我们来看一下数据范围:1 <= pattern.length <= 8,最多只有9位数,所以我们其实是可以通过暴力搜索来得出答案的:

回溯模拟,遍历到位置i时,我们查看在1-9中找到一个数,满足pattern[i],继续往下拼接。当遍历到结尾,我们找到了一个满足条件的数字,维护最小的即可。

var smallestNumber = function(pattern) {
    const used = new Array(10).fill(false);
    let ans;
    function dfs(str, i) {
        if (i >= pattern.length) {
            if (!ans || Number(str) < Number(ans)) {
                ans = str
            }
            return;
        }
        const v = pattern[i];
        const prev = str[i];
        for (let j = 1; j < 10; j++) {
            if (used[j]) continue;
            const bool = v === 'I' ? j > +prev : j < +prev;
            if (bool) {
                used[j] = true;
                dfs(str + j, i + 1)
                used[j] = false;
            }
        }
    }
    for (let i = 1; i < 10; i++) {
        used[i] = true;
        dfs(`${i}`, 0)
        used[i] = false;
    }
    return ans;
};

贪心,找规律

那么还有没有其他的方法呢?我们可以从下面几个点入手考虑一下是不是可以使用贪心思想来进行解答。

  • 字符串字典序最小

要使整个字符串的字典序最小,我们应该尽可能的将数值小的数字放在前面。

  • 当前下标位置最大取值

当前位置的最大取值与给出pattern相对位置的字符有关,如果当前位置是I(上升的),我们可以直接取当前没用过的数字的最小值即可,如果是D(下降的),那我们则需要预留出给其下降的空间,如DD,说明它需要连续下降两次,所以我们需要预留出一个数字。也就是说我们当前位置的取值会受到pattern相对位置后面连续D字符的数量的影响,所以我们只需要统计一下连续D的后缀个数即可,具体代码如下:

/**
 * @param {string} pattern
 * @return {string}
 */
 var smallestNumber = function(pattern) {
     let dd = new Array(pattern.length).fill(0);
     for(let j = pattern.length - 1; j >= 0 ; j--){
         if(j == pattern.length - 1) pattern[j] == 'D' ? dd[j] = 1 : '';
         else{
             if(pattern[j] == 'D') dd[j] = dd[j + 1] + 1;
         }
     }
     let res = '',ind = 0;
     for(let i = 0; i < pattern.length; i++){
         res += res.length + 1 + dd[i] - ind;
         if(dd[i]) ind++;
         else ind = 0;
     }
     if(pattern[pattern.length - 1] == 'I'){
         res += res.length + 1;
     }else{
        res += parseInt(res[res.length - 1]) - 1;
     }
     return res;
};

公众号

关注公众号『前端也能这么有趣』,获取更多有趣内容。

说在后面

🎉 这里是 JYeontu,现在是一名前端工程师,有空会刷刷算法题,平时喜欢打羽毛球 🏸 ,平时也喜欢写些东西,既为自己记录 📋,也希望可以对大家有那么一丢丢的帮助,写的不好望多多谅解 🙇,写错的地方望指出,定会认真改进 😊,偶尔也会在自己的公众号『前端也能这么有趣』发一些比较有趣的文章,有兴趣的也可以关注下。在此谢谢大家的支持,我们下文再见 🙌。

目录
相关文章
给定一个正整数N,将其表示为数字1,3,7,15相加的形式输出。请编码找出使上述数字出现的总次数最少(每个数字可以重复使用)的组合。
给定一个正整数N,将其表示为数字1,3,7,15相加的形式输出。请编码找出使上述数字出现的总次数最少(每个数字可以重复使用)的组合。
|
9月前
字符串,每个里面包含0-N个数字,如3,8,2,编写函数,将两个这样的字符串合并,并且输出的字符串里面没有重复的数字,并从大到小排列.
字符串,每个里面包含0-N个数字,如3,8,2,编写函数,将两个这样的字符串合并,并且输出的字符串里面没有重复的数字,并从大到小排列.
47 0
|
存储 算法 JavaScript
设计并实现一个函数, 功能为给定一个存储为随机整数的数组,从中删除所有值为i的整数
设计并实现一个函数, 功能为给定一个存储为随机整数的数组,从中删除所有值为i的整数
|
算法 JavaScript 前端开发
算法简单题,吾辈重拳出击 - 前 n 个数字二进制中 1 的个数
最近做的题,明眼人一看都能知道大都和动态规划 DP 有关,因为就是从动态规划分类下抽取的简单题,有的题在剑指 offer 系列中是简单题,但是在力扣主列表里确实中等难度的题目。 简单与难,也并非是绝对的,每个人的感受都会不同。更重要的是,通过这些题构建基础的算法思路,建立信心。
|
算法
如何在不把数字转为字符串的前提下反转数字
算法问题:如何在不把数字转为字符串的前提下反转数字
84 0
统计二进制中1的个数,,,写一个函数,返回参数二进制中1的个数 写一个代码判断一个数字是不是2的n次方
统计二进制中1的个数,,,写一个函数,返回参数二进制中1的个数 写一个代码判断一个数字是不是2的n次方
147 0
018.任意进制数的转换
018.任意进制数的转换
112 0
|
开发框架 .NET Java
C#基础——字符串、数字之间的转换
C#基础——字符串、数字之间的转换
474 0
C#基础——字符串、数字之间的转换