zoukankan      html  css  js  c++  java
  • JS Leetcode 1370. 上升下降字符串 题解分析,桶排序与charCodeAt fromCharCode妙用

    壹 ❀ 引

    本题来自LeetCode1370. 上升下降字符串,难度简单,是一道考察对于字符串遍历熟练度的题目,题目描述如下:

    给你一个字符串 s ,请你根据下面的算法重新构造字符串:

    从 s 中选出 最小 的字符,将它 接在 结果字符串的后面。
    从 s 剩余字符中选出 最小 的字符,且该字符比上一个添加的字符大,将它 接在 结果字符串后面。
    重复步骤 2 ,直到你没法从 s 中选择字符。
    从 s 中选出 最大 的字符,将它 接在 结果字符串的后面。
    从 s 剩余字符中选出 最大 的字符,且该字符比上一个添加的字符小,将它 接在 结果字符串后面。
    重复步骤 5 ,直到你没法从 s 中选择字符。
    重复步骤 1 到 6 ,直到 s 中所有字符都已经被选过。
    在任何一步中,如果最小或者最大字符不止一个 ,你可以选择其中任意一个,并将其添加到结果字符串。

    请你返回将 s 中字符重新排序后的 结果字符串 。

    示例 1:

    输入:s = "aaaabbbbcccc"
    输出:"abccbaabccba"
    

    解释:第一轮的步骤 1,2,3 后,结果字符串为 result = "abc"
    第一轮的步骤 4,5,6 后,结果字符串为 result = "abccba"
    第一轮结束,现在 s = "aabbcc" ,我们再次回到步骤 1
    第二轮的步骤 1,2,3 后,结果字符串为 result = "abccbaabc"
    第二轮的步骤 4,5,6 后,结果字符串为 result = "abccbaabccba"
    示例 2:

    输入:s = "rat"
    输出:"art"
    

    解释:单词 "rat" 在上述算法重排序以后变成 "art"
    示例 3:

    输入:s = "leetcode"
    输出:"cdelotee"
    

    示例 4:

    输入:s = "ggggggg"
    输出:"ggggggg"
    示例 5:

    输入:s = "spo"
    输出:"ops"
    

    提示:

    1 <= s.length <= 500
    s 只包含小写英文字母。

    让我们简单分析题意,然后实现它。

    贰 ❀ 桶排序与字符串常规API

    题目要求其实并不复杂,给定一个全部是小写字母的字符串,然后对此字符串进行取值拼接操作。我们先取当前字符串中的最小字符(每个字符只能使用一次),拼到一个空字符串上,然后继续找第二小的字符串,继续拼接操作。比如aab第一次取最小是a,那么第二次取最小时其实取得是b,因为这里的最小的定义是比上次大但在剩余字符串中最小。直到取不到最小之后,我们又开始取剩余字符串最大的字符,继续拼接操作,然后取第二大的字符继续拼接,当找不到符合条件的字符串之后,再执行前面的取最小操作,直到字符串被取空。

    aabbcc为例,它的过程其实就是这样:

    因为题目说明只包含小写字母,因此可能存在的字符情况一共也就16种,我们完全可以统计出a-z每个字符的出现频率,然后取最小就从左往右遍历数组取,取一个记得把这个字符串的数字减一,遍历到头后说明取小操作结束。紧接着从右往左遍历,开始取最大操作,重复上述操作,直到没有字符可取为止。

    因此到这里我们就可以使用桶排序,我们可以创建一个长度为26的数组,数组下标0表示a的位置,小标1表示字母b的位置,以这种方式来把所有字母次数都统计一次,具体怎么做呢?

    字符串中有一个API叫charCodeAt,它用于获取一个字符的Unicode编码,比如字母a的编码为:

    'a'.charCodeAt(0);//97
    'z'.charCodeAt(0);//122
    

    你会发现122-97=250-25一共正好26个数字,我们可以用每个字符串的编码减去97,比如'a'.charCodeAt(0)-97 = 0,它不就正好对应了数组下标0的位置,通过这种方式,我们就可以得到每个字符出现的次数,以及有序的与数组下标对应了。

    问题又来了,假设我们得到了最终数组[2,2,2],其实就是abc分别都出现了2次,当我们遍历到数组某个下标,知道它的值大于0,那就表示还有可以使用的字母,但是我们将这个数组的下标反向解析成字符串呢?其实与charCodeAt对应还有个API叫fromCharCode,它能将一个Unicode码反向解析成字符串,比如:

    String.fromCharCode(97+0);//a
    String.fromCharCode(97+1);//b
    

    而上述代码所加的数字,其实就是我们遍历到的当前的下标 i 。

    OK,解释了这些,我们可以来实现这段代码:

    /**
     * @param {string} s
     * @return {string}
     */
    var sortString = function (s) {
        // 创建一个有26个位置的空桶
        const bucket = new Array(26).fill(0);
        for (let i = 0; i < s.length; i++) {
            // 统计每个字母出现的次数
            bucket[s.charCodeAt(i) - 97]++;
        };
        let res = '';
        let len = s.length;
        while (len > 0) {
            // 取最小操作
            for (let i = 0; i < 26; i++) {
                // 如果有值,说明有字母可以使用
                if (bucket[i] > 0) {
                    // 拼接字符串
                    res += (String.fromCharCode(i + 97));
                    // 字符串都是一次性的,用了得减掉
                    bucket[i]--;
                    // 我们得保证整体的字符串长度也在递减,这样才知道什么时候字符串全部用完了。
                    len--;
                }
            }
            //取最大操作
            for (let i = 25; i >= 0; i--) {
                if (bucket[i] > 0) {
                    res += (String.fromCharCode(i + 97));
                    bucket[i]--;
                    len--;
                }
            }
        }
        return res;
    };
    

    那么本题就说到这里了

  • 相关阅读:
    序列化和反序列化
    自定义表达式解析器
    科学计算法帮助类MathUtils
    struts2接收参数的几种形式
    在matlab中实现遥感影像和shp文件的结合显示
    opencv实现正交匹配追踪算法OMP
    opencv实现canopy算法
    在matlab中实现线性回归和logistic回归
    在matlab中实现梯度下降法
    在matlab中实现PCA算法
  • 原文地址:https://www.cnblogs.com/echolun/p/14872756.html
Copyright © 2011-2022 走看看