算法笔记
本题是《代码随想录》当中讲到的回溯中组合问题的一道,主要区别在于不含有startIndex项,其次就是对于字符串与数字的一些处理,是道很容易出错的问题,本题采用C++编程。
题目描述
题目中给定了一个数字字符串,要我们返回所有有关于每个数字的组合,其中也存在不显示任何项的内容,那么除了回溯之外我们需要做到的基本操作主要是如何让数字对应相应的字符串以及分割digits字符串为单个数字。
解题过程
在开始我们的老三样–三部曲之前,我想重点讨论之前提到的基本操作的实现。
首先题目中给出的电话号码【除了#号*号】各代表了属于自己的一串字符,其中0和1对应的是" ",其余部分都对应字母,那么就可以先定义一个字符串数组可以叫做phonenumber,使用const是因为在之后这部分不会变动,这些处理好一些。
const string phonenumber[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};//0-9
之后的基本操作需要分开字符串,这里我们先引入一个参数index,这个数字不同于以往定位初始位置的startIndex,而是用于表示输入数字串当中的第几个,例如实例中"23",那么第一个就是2,第二个就是3。
引入之后就可以开始操作了,这里分为两步。
**第一步:**把数字串的每个数字字符变为数字本身,使用以下代码,为什么减去"0"可以去参照ASCII表。
int digit = digits[index] - '0';
**第二步:**将拆分的每一个数字作为开始定义的电话号码数组索引辅助定义一个串phone,这个字符串的长度就是我们转化为树中树的宽度。基本操作结束就可以三部曲了。
string phone = phonenumber[digit];
三部曲:
1.**选择参数:**同之前的组合问题一样,除了给定函数的参数以外,我们需要记录路径的参数与记录结果的参数,这里不需要二维数组,直接使用一个一维数组result就可以记录结果,原先本应定义的一维数组使用一个字符串s就可以了,再加上上文提到的参数index就基本取到了所有参数。
2.**终止条件:**如果我们定义的索引index在一步步往后增加的过程中等于输入的字符串digits的长度,那么我们就可以使用result记录结果并返回。另外后面也要说明字符串长度为0时直接返回即可。
3.**循环递归回溯:**for循环里面注意条件,这个i小于字符串phone的大小时就跳出循环即可,这里面phone.size()我们可以理解为之前组合问题当中的k,表示几个数的组合,之后用s记录路径即可。在递归部分index作为索引需要不断增大,所以后一个参数应为index + 1。最后就是简单的回溯从哪来回哪去,撤回节点,结束整部分代码。
代码部分
class Solution {
private:
const string phonenumber[10] = {"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"};
public:
vector<string> result;
string s;
void backtracking(const string& digits, int index) {
if(index == digits.size()) {
result.push_back(s);
return;
}
int digit = digits[index] - '0';
string phone = phonenumber[digit];
for(int i = 0; i < phone.size(); i++) {
s.push_back(phone[i]);
backtracking(digits, index + 1);
s.pop_back();
}
}
vector<string> letterCombinations(string digits) {
if(digits.size() == 0) {
return result;
}
backtracking(digits, 0);
return result;
}
};
结语
本题是一道经过包装的组合问题,在有关于组合中回溯的部分并不难实现,个人认为主要问题还是出自于题目描述提到的基本操作当中,我们可以借这道题去好好学习一下字符串部分的相关知识,练习相应的题目。