leetcode 17. 电话号码的字母组合----回溯算法

Posted 大忽悠爱忽悠

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode 17. 电话号码的字母组合----回溯算法相关的知识,希望对你有一定的参考价值。

在这里插入图片描述

在这里插入图片描述


电话号码的字母组合题解集合


引言

如果对回溯算法不了解的,建议先看这篇文章
小白易懂的回溯算法!!!


回溯算法

将问题转化为对一颗多叉树的遍历过程,可以大大简化思维和实现难度
在这里插入图片描述

在这里插入图片描述
由上图可得:

  • 递归结束条件: 输入的数字个数与当前已经找到的字母个数一致,说明找到了一个可行方案,然后将可行方案保存到ret数组中
  • 递归返回值:void
  • 本级递归做什么:遍历当前数字对应剩余的字母,看能否找到其余解

代码:

class Solution {
	unordered_map<char, string> map;//保存每个数字映射的字母
	vector<string> ret;//保存所有结果组合
public:
	vector<string> letterCombinations(string digits) 
	{
		if (digits.empty()) return ret;
		//保存每个数字映射的字母
		map['2'] = "abc";
		map['3'] = "def";
		map['4'] = "ghi";
		map['5'] = "jkl";
		map['6'] = "mno";
		map['7'] = "pqrs";
		map['8'] = "tuv";
		map['9'] = "wxyz";

		//组合需要的字母个数
		int num = digits.size();
		string cur;
		dfs(digits, cur,num,0);
		return ret;
	}
	//cur将找到的字母先存放在里面,等到字母个数等于需要的个数时,再压入结果数组
	//num: 组合需要的字母个数
	//n:当前用到了第一个数字
	void dfs(string digits,string cur,int num,int n)
	{
		if (cur.size() == num)//找到了一个可行解
		{
			ret.push_back(cur);
			return;
		}
		//遍历当前数字剩余的字母
		for (int i = 0; i < map[digits[n]].size(); i++)//注意这里每一层,都是从第一个字母开始进行遍历
		{
			//把当前数字对应的第index个字母放入cur数组中
			cur.push_back(map[digits[n]][i]);
			//遍历剩余字母
			dfs(digits, cur,num, n + 1);
			//回溯
			cur.pop_back();
		}
	}

};

在这里插入图片描述


BFS—队列求解

其实上面的DFS的思路就是先选取第一个数字对应的第一个字母,然后去下一层与第二个数字的三个字母分别进行组合,组合完后,再取第一个数字对应的第二个字母,同样去下一层与第二个数字的三个字母进行组合,接着是第一个数字对应的第三个字母…

那么这里同样可以利用BFS的方法实现上述思路,看图:

我们可以利用队列的先进先出特点,再配合循环完成题目要求。

我们先将2对应的字符"a",“b”,“c"依次放入队列中
在这里插入图片描述
之后再从队列中拿出第一个元素"a”,跟3对应的字符"d",“e”,“f"挨个拼接
在这里插入图片描述
于是队列就变成了下面这个样子:
在这里插入图片描述
按照同样的方式,再将"b"从队列中拿出,再跟3对应的字符"d”,“e”,"f"挨个拼接,队列又变成下面这个样子:
在这里插入图片描述
注意这里BFS的思路:

新一层在上一层的末尾添加字符得到;

新一层得到了以后,上一层就不用了;

最开始的时候,是一个空字符串。

代码;

class Solution {
	unordered_map<char, string> store;
	vector<string> ret;//保存所有结果组合
public:
	vector<string> letterCombinations(string digits) 
	{
		if (digits.empty()) return ret;
		//储存字典
		store = unordered_map<char, string>{
			{'2', "abc"}, {'3', "def"}, {'4', "ghi"}, {'5', "jkl"}, {'6', "mno"}, {'7', "pqrs"}, {'8', "tuv"}, {'9', "wxyz"} };
		//组合需要的字母个数
		int num = digits.size();
		string cur;
		queue<string> q;
		q.push("");
		for (auto cur : digits)//cur表示遍历的当前层
		{
			string curStr = store[cur];//获取当前数字对应的字符串---即需要进行遍历的字母
			int size = q.size();//获取当前队列的长度
			//将当前层元素出队
			for (int i = 0; i < size; i++)
			{
				string tempStr = q.front();
				q.pop();
				for (auto tempChar : curStr)//将下一层元素前面加上当前要出队元素后,入队
				{
					q.push(tempStr + tempChar);
				}
			}
		}
		while (!q.empty())
		{
			string tempStr = q.front(); q.pop();
			ret.push_back(tempStr);
		}
		return ret;
	}
};

在这里插入图片描述


总结

本题主要还是想要大家理解回溯算法的思想,而BFS只是作为一个扩展。

下面我来总结一下回溯算法的基本模板:

确定结束回溯过程的 Base case

遍历所有的选择

对选择进行决策(做选择--->递归---->撤销选择)

伪代码:

void dfs(路径,选择列表,结果集)
{
  if(满足结束条件)
  {
    结果集.add(路径);
    return;
  }
  for(选择:选择列表)
  {
  做选择;
   dfs(路径,选择列表,结果集);
   撤销选择;
  }
}

以上是关于leetcode 17. 电话号码的字母组合----回溯算法的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 17.电话号码的字母组合

LeetCode #17 电话号码的字母组合

LeetCode17. 电话号码的字母组合

[LeetCode] 17. 电话号码的字母组合

[JavaScript 刷题] 搜索 - 电话号码的字母组合, leetcode 17

LeetCode 17. 电话号码的字母组合