鸿蒙应用开发实战【19】— 统计卡片组件:数字展示、颜色语义与点击导航
2026/7/16 5:04:46
给定一个仅包含数字2-9的字符串,返回所有它能表示的字母组合。答案可以按任意顺序返回。
数字到字母的映射与电话按键一致(1 不对应任何字母):
示例 1:输入:digits = "23"输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:输入:digits = "2"输出:["a","b","c"]
示例 3:输入:digits = ""输出:[]
中等
这是一道典型的组合型回溯问题,核心逻辑是:
n个数字(所有数字处理完毕),将路径加入结果;#include <iostream> #include <vector> #include <string> using namespace std; class Solution { // 数字到字母的映射表,索引对应数字0-9 static constexpr string MAPPING[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; public: vector<string> letterCombinations(string digits) { int n = digits.length(); // 边界条件:空字符串直接返回空数组 if (n == 0) { return {}; } vector<string> ans; // 存储最终结果 string path(n, 0); // 路径字符串,长度固定为n,避免频繁拼接 // 递归lambda表达式(C++14及以上支持this auto&&) auto dfs = [&](this auto&& dfs, int i) -> void { // 递归终止:处理完所有数字 if (i == n) { ans.emplace_back(path); // 将当前路径加入结果 return; } // 获取当前数字对应的字母串 const string& letters = MAPPING[digits[i] - '0']; // 遍历当前数字的所有字母 for (char c : letters) { path[i] = c; // 直接覆盖路径的第i位,无需拼接/回退 dfs(i + 1); // 递归处理下一个数字 } }; dfs(0); // 从第0个数字开始递归 return ans; } }; // 测试函数 void test() { Solution s; // 测试案例1 vector<string> res1 = s.letterCombinations("23"); cout << "输入: 23 | 输出: "; for (const string& str : res1) { cout << str << " "; } cout << endl; // 测试案例2 vector<string> res2 = s.letterCombinations("2"); cout << "输入: 2 | 输出: "; for (const string& str : res2) { cout << str << " "; } cout << endl; // 测试案例3 vector<string> res3 = s.letterCombinations(""); cout << "输入: 空 | 输出: " << (res3.empty() ? "空数组" : "非空") << endl; } int main() { test(); return 0; }static constexpr string MAPPING[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};static constexpr定义常量映射表,避免每次调用函数时重复创建,提升性能;if (n == 0) { return {}; }string path(n, 0);n的路径字符串,通过覆盖指定位置的方式构建组合,无需回退操作,减少字符串拼接 / 删除的开销。auto dfs = [&](this auto&& dfs, int i) -> void { ... };this auto&& dfs表示 lambda 自身的引用,用于递归调用;[&]表示按引用捕获外部变量(ans、path、digits、MAPPING)。if (i == n) { ans.emplace_back(path); return; } for (char c : letters) { path[i] = c; dfs(i + 1); }i == n表示所有数字处理完毕,将当前路径加入结果集;i位,递归处理下一个数字(i+1);pop_back操作),代码更简洁。输入: 23 | 输出: ad ae af bd be bf cd ce cf 输入: 2 | 输出: a b c 输入: 空 | 输出: 空数组
完全符合题目预期。
n,每个数字对应k个字母(k∈[3,4]);3^n或4^n(取决于数字对应的字母数);O(3^n ~ 4^n),即所有组合的总数。n(数字长度);O(n)空间;O(3^n ~ 4^n)空间(存储所有组合);O(3^n ~ 4^n)。如果不想使用递归,也可以通过迭代的方式实现:
vector<string> letterCombinations_iter(string digits) { if (digits.empty()) return {}; vector<string> ans = {""}; for (char d : digits) { vector<string> temp; const string& letters = MAPPING[d - '0']; for (const string& s : ans) { for (char c : letters) { temp.push_back(s + c); } } ans.swap(temp); } return ans; }static constexpr,避免重复初始化,提升性能;本题是回溯算法的经典入门题,核心在于理解「逐步构建组合 + 递归遍历」的思想。本文提供的实现方案有以下特点:
掌握本题的回溯思想后,可进一步解决类似的组合问题(如组合总和、子集等),是算法学习中不可或缺的基础知识点。