1.基础知识
回溯算法本质就是穷举,可以就填充不行就回溯
回溯模板:
(1)return条件
(2)for循环遍历,{
每次递归时操作;
递归;
回溯;
}
2.刷题
77.组合问题
回溯
理解思路,很精巧:
1.path.pop_back回溯:先得到{1} ;递归得到{1,2},此时path.size()==k,return再path.pop_bac回溯 ;得到 {1,3}以此类推,最终得到{1,n}。同时startIndex可以确保数字递增不重复!
2.for循环实现单层横向遍历。
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(int n,int k,int startIndex){
if(path.size()==k)
{
result.push_back(path);
return;
}
for(int i=startIndex;i<=n;i++){
path.push_back(i);
backtracking(n,k,i+1);
path.pop_back();
}
}
public:
vector<vector<int>> combine(int n, int k) {
backtracking(n,k,1);
return result;
}
};
剪枝
如果n-startIndex<k,此时递归结束path.size()必然小于k(因为path.size()都不一定为0),没有必要遍历了。因此for循环条件可以修改为
for(int i=startIndex;i<=n-(k-path.size())+1;i++)
216.组合总和III.
同上题,一直出错发现return写错行了,注意代码规范性
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(int index,int k,int n){
if(path.size()==k){
if(accumulate(path.begin(),path.end(),0)==n){
result.push_back(path);
}return;
}
for(int i=index;i<=9-(k-path.size())+1;i++){
path.push_back(i);
backtracking(i+1,k,n);
path.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
backtracking(1,k,n);
return result;
}
};
17.电话号码的字母组合
本题基础语法不熟练,多刷
Q1.怎么将数字与字母对应起来?
有多种选择:map,unordered_map或是const string map[10]
1. std::map
和 std::unordered_map
的使用情况
std::map
(有序映射)
std::map
是一种基于平衡二叉树(通常是红黑树)实现的有序映射,它会按照key值的顺序自动排列键。
-
适用场景:
- 需要有序数据:如果你需要保持key的顺序,可以使用
std::map
。它会根据key的大小自动排序,例如按字典顺序或者数值大小排序。 - 区间查询:如果你需要进行类似查找最小值、最大值,或者执行区间查询(例如查找key在某一范围内的所有元素)时,
std::map
更加合适,因为它会保持key的有序性。 - 时间复杂度和内存:
std::map
的时间复杂度是 O(log N),因为它基于红黑树,因此查询、插入、删除操作的时间复杂度是对数级别。它也比std::unordered_map
使用更多的内存,因为要维持树的结构。
- 需要有序数据:如果你需要保持key的顺序,可以使用
-
const map
的使用:- 如果你希望在定义的
map
之后不再修改它的数据,可以将其声明为const
。这会确保该映射不被修改(不能进行插入或删除操作),但仍然可以读取其中的值。
- 如果你希望在定义的
-
代码示例:
#include <iostream> #include <map> int main() { const std::map<int, std::string> orderedMap = { { 3, "Three"}, { 1, "One"}, { 2, "Two"}}; // 输出会按照键的顺序(从小到大)打印 for (const auto& pair : orderedMap) { std::cout << pair.first << ": " << pair.second << std::endl; } // 由于是 const,因此不能修改 map // orderedMap[4] = "Four"; // 会报错! return 0; }
输出:
1: One 2: Two 3: Three
std::unordered_map
(哈希映射)
std::unordered_map
是一种基于哈希表实现的无序映射,它不会按照键的顺序存储元素。
-
适用场景:
- 快速查找:如果你不关心键的顺序,并且需要进行高效的查找、插入和删除操作,
std::unordered_map
更为合适。它的查找、插入、删除操作平均时间复杂度为 O(1),因此适用于大规模数据存储和快速查询的场景。 - 哈希操作:当你需要对键进行哈希操作时,
std::unordered_map
是一个很好的选择。
- 快速查找:如果你不关心键的顺序,并且需要进行高效的查找、插入和删除操作,
-
const unordered_map
的使用:- 如果你希望
unordered_map
中的内容不可修改,可以将其声明为const
,这意味着你不能在后续修改该映射的内容,只能进行查询。
- 如果你希望
-
代码示例:
#include <iostream> #include <unordered_map> int main() { const std::unordered_map<int, std::string> unorderedMap = { { 3, "Three"}, { 1, "One"}, { 2, "Two"}}; // 输出的顺序是不可预测的,因为哈希映射没有顺序 for (const auto& pair : unorderedMap) { std::cout << pair.first << ": " << pair.second << std::endl; } // 由于是 const,因此不能修改 map // unorderedMap[4] = "Four"; // 会报错! return 0; }
输出(顺序可能不同):
1: One 2: Two 3: Three
2. const string letterMap[10]
的对比
const string letterMap[10];
-
定义解释:
const
:表示该数组是常量,数组中的元素一旦初始化后就不能被修改。string
:数组的元素类型是std::string
,也就是说,letterMap
数组中的每个元素都是一个字符串。letterMap[10]
:表示数组的大小是 10,意味着这个数组最多能存储 10 个std::string
类型的元素。
-
与
std::map
和std::unordered_map
的区别:- 大小固定:
letterMap[10]
是一个大小为 10 的静态数组,大小在编译时就已经确定,并且无法动态扩展。如果需要存储更多或更少的元素,需要手动调整数组的大小。 - 没有键值对结构:
letterMap
只是一个简单的数组,其中的元素按索引排列,没有明确的键值对关系。你不能像在std::map
或std::unordered_map
中那样通过键来访问元素。 - 性能:数组具有常数时间的访问效率(O(1)),因为可以通过索引直接访问元素,而
std::map
和std::unordered_map
的查找效率则依赖于其实现(树或哈希表)。
- 大小固定:
主要区别:
std::map
和std::unordered_map
都是动态数据结构,可以存储任意数量的元素,而letterMap[10]
是一个固定大小的静态数组,大小固定为 10。std::map
会保持键的顺序,而letterMap[10]
没有顺序,它只是一个简单的数组。std::unordered_map
提供了快速查找的特性,而letterMap[10]
是通过索引来访问的。
总结
- 使用
std::map
:当你需要保证元素按键排序,并且需要在有序的数据上进行操作时。 - 使用
std::unordered_map
:当你不关心顺序并且需要高效的插入、删除和查找操作时。 - 使用
letterMap[10]
:当你知道需要一个固定大小的数组,并且不需要按键查找数据时,可以使用简单的数组。如果你想要动态数据存储,std::map
或std::unordered_map
会更加合适。
class Solution {
private:
//如何定义键盘与字母的对应关系
const string lettermap[10] = {
"", "", "abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz",
};
public:
//这里定义result是string类型
vector<string> result;
string path;
void backtracking(const string& digits, int index) {
if (path.size() == digits.size()) {
result.push_back(path);
return;
}
//递归过程实现深度
//将输入的每位字符转化成数字
int dight = digits[index] - '0';
//获得对应字符代表的几个字母,作为一个单独的字符串,用for循环查找
string cur = lettermap[dight];
for (int i = 0; i < cur.length(); i++) {
path.push_back(cur[i]);
backtracking(digits, index + 1);
//记得回溯
path.pop_back();
}
}
vector<string> letterCombinations(string digits) {
//需要排除size==0的情况,从而得到[],否则会输出[""]