Medium
题目描述
给你一个字符串 word,其中包含小写英文字母。
电话键盘上的按键映射到不同的小写英文字母集合,可以通过按压按键来组成单词。例如,按键 2 映射到 [“a”,“b”,“c”],我们需要按一次来输入 “a”,按两次来输入 “b”,按三次来输入 “c”。
可以将编号为 2 到 9 的按键重新映射到不同的字母集合。按键可以映射到任意数量的字母,但每个字母必须恰好映射到一个按键上。你需要找到输入字符串 word 所需的最少按键次数。
返回重新映射按键后输入 word 所需的最少按压次数。
示例 1:
输入:word = "abcde"
输出:5
解释:重新映射的键盘提供最小代价。
"a" -> 在按键 2 上按一次
"b" -> 在按键 3 上按一次
"c" -> 在按键 4 上按一次
"d" -> 在按键 5 上按一次
"e" -> 在按键 6 上按一次
总代价是 1 + 1 + 1 + 1 + 1 = 5。
可以证明没有其他映射能提供更低的代价。
示例 2:
输入:word = "xyzxyzxyzxyz"
输出:12
解释:重新映射的键盘提供最小代价。
"x" -> 在按键 2 上按一次
"y" -> 在按键 3 上按一次
"z" -> 在按键 4 上按一次
总代价是 1 * 4 + 1 * 4 + 1 * 4 = 12
示例 3:
输入:word = "aabbccddeeffgghhiiiiii"
输出:24
解释:重新映射的键盘提供最小代价。
总代价是 24。
约束:
1 <= word.length <= 10^5word由小写英文字母组成。
解题思路
这是一个典型的贪心算法问题。我们需要最小化总的按键次数,关键是理解按键的分配策略。
核心思路:
- 我们有8个可用的按键(2-9),每个按键可以映射多个字母
- 在同一个按键上,第1个字母需要按1次,第2个字母需要按2次,以此类推
- 为了最小化总按键次数,应该把出现频率最高的字母放在最容易按到的位置
算法步骤:
- 统计每个字母的出现频率
- 将字母按频率从高到低排序
- 贪心分配:前8个字母各占一个按键的第1位(按1次),接下来8个字母各占一个按键的第2位(按2次),以此类推
- 计算总的按键次数
时间复杂度分析:
- 统计频率:O(n)
- 排序:O(26log26) = O(1),因为字母数量固定
- 计算结果:O(26) = O(1)
- 总体:O(n)
这种贪心策略是正确的,因为我们总是优先给频率高的字母分配更少的按键次数。
代码实现
class Solution {
public:
int minimumPushes(string word) {
vector<int> freq(26, 0);
for (char c : word) {
freq[c - 'a']++;
}
sort(freq.rbegin(), freq.rend());
int result = 0;
for (int i = 0; i < 26; i++) {
if (freq[i] == 0) break;
int pushes = i / 8 + 1;
result += freq[i] * pushes;
}
return result;
}
};
class Solution:
def minimumPushes(self, word: str) -> int:
from collections import Counter
freq = Counter(word)
sorted_freq = sorted(freq.values(), reverse=True)
result = 0
for i, count in enumerate(sorted_freq):
pushes = i // 8 + 1
result += count * pushes
return result
public class Solution {
public int MinimumPushes(string word) {
int[] freq = new int[26];
foreach (char c in word) {
freq[c - 'a']++;
}
Array.Sort(freq, (a, b) => b.CompareTo(a));
int result = 0;
for (int i = 0; i < 26; i++) {
if (freq[i] == 0) break;
int pushes = i / 8 + 1;
result += freq[i] * pushes;
}
return result;
}
}
var minimumPushes = function(word) {
const freq = new Array(26).fill(0);
for (const c of word) {
freq[c.charCodeAt(0) - 97]++;
}
freq.sort((a, b) => b - a);
let result = 0;
for (let i = 0; i < 26; i++) {
if (freq[i]
复杂度分析
| 操作 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 统计字母频率 | O(n) | O(1) |
| 排序频率数组 | O(1) | O(1) |
| 计算最少按键次数 | O(1) | O(1) |
| 总体 | O(n) | O(1) |
其中 n 是字符串 word 的长度。空间复杂度为 O(1) 是因为字母种类固定为 26 个。