【一天一大 lee】上升下降字符串 (难度:简单) - Day20201125

20201125

题目:

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

  1. 从 s 中选出最小的字符,将它接在结果字符串的后面。
  2. 从 s 剩余字符中选出最小的字符,且该字符比上一个添加的字符大,将它接在结果字符串后面。
  3. 重复步骤 2 ,直到你没法从 s 中选择字符。
  4. 从 s 中选出最大的字符,将它接在结果字符串的后面。
  5. 从 s 剩余字符中选出最大 的字符,且该字符比上一个添加的字符小,将它接在结果字符串后面。
  6. 重复步骤 5 ,直到你没法从 s 中选择字符。
  7. 重复步骤 1 到 6 ,直到 s 中所有字符都已经被选过。

在任何一步中,如果最小或者最大字符不止一个,你可以选择其中任意一个,并将其添加到结果字符串。

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

示例:

  1. 示例 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"
  1. 示例 2:
入:s = "rat"
输出:"art"
解释:单词 "rat" 在上述算法重排序以后变成 "art"
  1. 示例 3:
输入:s = "leetcode"
输出:"cdelotee"
  1. 示例 4:
输入:s = "ggggggg"
输出:"ggggggg"
  1. 示例 5:
输入:s = "spo"
输出:"ops"

提示:

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

抛砖引玉

本题的逻辑主要是:

  • 先按照小到大拼接一次元素(每个元素只取一次)
  • 再从大到小拼接一次元素
  • 直到所有元素都被重新拼接

利用哈希记录字符在 s 中出现的次数,利用数组排序来完成上面从大到小&从小到大的排序:

  • 对 s 去重排序后直接整体拼接
  • 整体拼接一次所有字符出现次数减 1,如果出现次数归 0,则将其从排序 list 中清除
  • 翻转数组(从大到小-从小到大转换)待下次拼接

抛砖引玉

/**
 * @param {string} s
 * @return {string}
 */
var sortString = function(s) {
    let map = new Map(),
        list = [],
        result = [],
        len = s.length,
        max = 1
    //    初始化哈希计算和list无重复元素数组
    for (let i = 0; i < len; i++) {
        if (map.has(s[i])) {
            const num = map.get(s[i]) + 1
            map.set(s[i], num)
            max = Math.max(max, num)
        } else {
            map.set(s[i], 1)
            list.push(s[i])
        }
    }
    // 对字符排序
    list.sort()
    // 最多拼接次数
    while (max) {
        // 完成一次拼接,哈希计算-1
        result = [...result, ...list]
        for (let [key, value] of map.entries()) {
            const num = value - 1
            if (num) {
                map.set(key, num)
            } else {
                // 如果计算归0,则删除这个字符
                map.delete(key)
                list.splice(list.indexOf(key), 1)
            }
        }
        // 翻转数组 转换排序
        list.reverse()
        max--
    }
    return result.join('')
}

桶计数

  • 利用字符的 UTF-16 代码在数组中占位,记录元素数组(完成排序和计算两个逻辑)
  • 循环多次拼接知道所有字符拼接完成
var sortString = function(s) {
    let list = new Array(26).fill(0),
        len = s.length
    for (let i = 0; i < len; i++) {
        list[s.charCodeAt(i) - 97]++
    }
    let result = ''
    while (len) {
        // 从小到大
        for (let i = 0; i < 26; i++) {
            if (list[i]) {
                result += String.fromCharCode(i + 97)
                list[i]--
                len--
            }
        }
        // 从大到小
        for (let i = 25; i >= 0; i--) {
            if (list[i]) {
                result += String.fromCharCode(i + 97)
                list[i]--
                len--
            }
        }
    }
    return result
}

博客: 前端小书童

每天的每日一题,写的题解会同步更新到公众号一天一大 lee 栏目
欢迎关注留言

公众号:前端小书童

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值