跳至主要內容

1370. 上升下降字符串


1370. 上升下降字符串

🟢   🔖  哈希表 字符串 计数  🔗 力扣open in new window LeetCodeopen in new window

题目

You are given a string s. Reorder the string using the following algorithm:

  1. Remove the smallest character from s and append it to the result.
  2. Remove the smallest character from s that is greater than the last appended character, and append it to the result.
  3. Repeat step 2 until no more characters can be removed.
  4. Remove the largest character from s and append it to the result.
  5. Remove the largest character from s that is smaller than the last appended character, and append it to the result.
  6. Repeat step 5 until no more characters can be removed.
  7. Repeat steps 1 through 6 until all characters from s have been removed.

If the smallest or largest character appears more than once, you may choose any occurrence to append to the result.

Return the resulting string after reordering s using this algorithm.

Example 1:

Input: s = "aaaabbbbcccc"

Output: "abccbaabccba"

Explanation: After steps 1, 2 and 3 of the first iteration, result = "abc"

After steps 4, 5 and 6 of the first iteration, result = "abccba"

First iteration is done. Now s = "aabbcc" and we go back to step 1

After steps 1, 2 and 3 of the second iteration, result = "abccbaabc"

After steps 4, 5 and 6 of the second iteration, result = "abccbaabccba"

Example 2:

Input: s = "rat"

Output: "art"

Explanation: The word "rat" becomes "art" after re-ordering it with the mentioned algorithm.

Constraints:

  • 1 <= s.length <= 500
  • s consists of only lowercase English letters.

题目大意

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

  1. s 中选出 最小 的字符,将它 接在 结果字符串的后面。
  2. s 剩余字符中选出比上一个添加字符更大的 最小 字符,将它 接在 结果字符串后面。
  3. 重复步骤 2 ,直到你没法从 s 中选择字符。
  4. s 中选出 最大 的字符,将它 接在 结果字符串的后面。
  5. s 剩余字符中选出比上一个添加字符更小的 最大 字符,将它 接在 结果字符串后面。
  6. 重复步骤 5 ,直到你没法从 s 中选择字符。
  7. 重复步骤 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"

提示:

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

解题思路

  1. 统计每个字符的出现次数:

    • 使用一个长度为 26 的数组 count,表示字符 'a''z' 的出现次数。
    • 遍历字符串 s,通过字符的 ASCII 值计算其索引位置: count[char.charCodeAt() - 'a'.charCodeAt()]++
  2. 按照规则构建结果字符串:

    • 使用一个结果字符串 res
    • res 的长度小于 s 的长度时,不断执行以下两个步骤:
      • 从左到右(字典序递增)扫描 count 数组,将字符添加到结果字符串中并减少对应的计数。
      • 从右到左(字典序递减)扫描 count 数组,将字符添加到结果字符串中并减少对应的计数。
  3. 返回结果字符串:

    • 重复上述操作,直到所有字符用完,最终返回 res

复杂度分析

  • 时间复杂度O(n),其中 n 为字符串的长度。
    • 统计字符次数,遍历字符串 s,复杂度为 O(n)
    • 构造结果字符串,每次遍历 count 数组需要 O(26),总共构造字符串的长度为 n,复杂度为 O(26 * n),即 O(n)
  • 空间复杂度O(n)
    • count 数组大小固定为 26,空间复杂度为 O(1)
    • 结果字符串的空间复杂度为 O(n)

代码

var sortString = function (s) {
	let count = new Array(26).fill(0); // 初始化字符计数数组
	// 统计每个字符的出现次数
	for (let char of s) {
		count[char.charCodeAt() - 'a'.charCodeAt()]++;
	}

	let res = ''; // 结果字符串

	while (res.length < s.length) {
		// 当结果字符串未完成时,继续操作
		for (let i = 0; i < 26; i++) {
			// 从左到右(字典序递增)
			if (count[i] > 0) {
				res += String.fromCharCode(i + 'a'.charCodeAt());
				count[i]--;
			}
		}
		for (let i = 25; i >= 0; i--) {
			// 从右到左(字典序递减)
			if (count[i] > 0) {
				res += String.fromCharCode(i + 'a'.charCodeAt());
				count[i]--;
			}
		}
	}

	return res; // 返回结果字符串
};