17 电话号码的字母组合
中等题
一道排列组合的题目。很容易发现每次都是在上次的结果上循环,只是可供选择的字母数可能是3或4。此类明显带有“这次是结果是在上次基础上完成的”特征的题目,通常都能用动态规划解决,因为明显告诉了递推关系。
动态规划问三个问题:
- 状态。这题使用一维数组存储即可,dp[i]表示输入i个字母后所有的排列组合情况的数组。
- 递推表达式。已知dp[i],求dp[i+1]就是把dp[i]中的组合分别加上第i+1个数字可能表示的字母。
- 初始值。dp[0]表示没有数字进来,应该是空数组。不过为了后面方便遍历,可以存一个空字符串。
按照以上思路编写代码,只是我不太会C++的数组动态分配,用循环需要一开始开辟大数组,索性直接递归了,反正要循环的次数是少不了的。
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<string> letterCombinations(string digits) {
vector<vector<string>> key = {
{""}, //0
{""}, //1
{"a","b","c"}, //2
{"d","e","f"}, //3
{"g","h","i"}, //4
{"j","k","l"}, //5
{"m","n","o"}, //6
{"p","q","r","s"}, //7
{"t","u","v"}, //8
{"w","x","y","z"} //9
};
if(digits=="") return vector<string>();
return constituten(key,digits,digits.size());
}
vector<string> constituten(vector<vector<string>> key, string digits, int loc){
if(loc == 0) return vector<string>({string()});
vector<string> res;
vector<string> prv = constituten(key,digits,loc-1);
int num = digits[loc-1] - 48;
for(int i=0; i<key[num].size(); i++){
for(int j=0; j<prv.size(); j++){
res.push_back(prv[j]+key[num][i]);
}
}
return res;
}
};
int main(){
string digits = "";
Solution st;
vector<string> vt;
vt=st.letterCombinations(digits);
return 0;
}
官解给出回溯法,是使用搜索的思想吧,个人觉得在这题没有那么明显,下次遇到再分析吧。
18 四数之和
中等题
三数找完找四数,我的精神内耗都这几个叔治好啦。
解题思路和三数完全一样,多一层循环,也是双指针。测试用例里非要搞个溢出,那就补上处理溢出操作。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int len = nums.size();
vector<vector<int>> res = {};
if(len<4) return res;
sort(nums.begin(),nums.end()); //排序
for(int first=0; first<len-3; first++){
//一层循环
if(first!=0 && nums[first-1] == nums[first]) continue;
for(int second=first+1; second<len-2; second++){
//二层循环
if(second!=first+1 && nums[second-1] == nums[second]) continue;
int forth = len-1;
for(int third = second+1; third<len-1; third++){
//三重循环
if(third!=second+1 && nums[third-1] == nums[third]) continue;
while(third<forth){
long half = (long)target-nums[first]-nums[second];
if(nums[third]+nums[forth] == half){
res.push_back(vector<int>({nums[first],nums[second],nums[third],nums[forth]}));
break;
}
if(nums[third]+nums[forth] > target-nums[first]-nums[second]) forth--;
else break;
}
}
}
}
return res;
}
};
int main(){
Solution st;
vector<int> vt = {1,0,-1,0,-2,2};
int target = 0;
vector<vector<int>> res;
res = st.fourSum(vt,target);
return 0;
}