代码随想录刷题题Day21

刷题的第二十一天,希望自己能够不断坚持下去,迎来蜕变。
刷题语言:C++
Day21 任务
● 216.组合总和III
● 17.电话号码的字母组合

1 组合总和III

216.组合总和III
代码随想录刷题题Day21_第1张图片
思路:

在[1,2,3,4,5,6,7,8,9]这个集合中找到和为n的k个数的组合

代码随想录刷题题Day21_第2张图片
(1)确定递归函数参数,返回值
返回值:void
参数:目标和n,k,sum(已经收集的元素的总和),startIndex

vector<vector<int>> result;
vector<int>path;
void backtracking(int n, int k, int sum, int startIndex)

(2)确认终止条件

if (path.size() == k) {
	if (sum == n) result.push_back(path);
	return;
}

(3)单层搜索过程

path收集每次选取的元素,sum来统计path里元素的总和

for (int i = startIndex; i <= 9; i++) {
	sum += i;
	path.push_back(i);
	backtracking(n, k, sum, i + 1); // 注意i+1调整startIndex
	sum -= i;// 回溯
	path.pop_back();// 回溯
}

C++:

class Solution {
public:
    vector<vector<int>> result;// 存放结果集
    vector<int> path;// 符合条件的结果
    void traversal(int n, int k, int sum, int startIndex) {
        if (path.size() == k) {
            if (sum == n) result.push_back(path);
            return;// 如果path.size() == k 但sum != targetSum 直接返回
        }
        for (int i = startIndex; i <= 9; i++) {
            sum += i;// 处理
            path.push_back(i);// 处理
            traversal(n, k, sum, i + 1);// 注意i+1调整startIndex
            sum -= i;// 回溯
            path.pop_back();// 回溯
        }

    }
    vector<vector<int>> combinationSum3(int k, int n) {
        traversal(n, k, 0, 1);
        return result;
    }
};

剪枝优化:
(1)已选元素总和如果已经大于n,那么往后遍历就没有意义

剪枝的地方可以放在递归函数开始的地方

if (sum > n) return;

(2)for循环的范围也可以剪枝,i <= 9 - (k - path.size()) + 1

剪枝优化C++:

class Solution {
public:
    vector<vector<int>> result;
    vector<int> path;
    void traversal(int n, int k, int sum, int startIndex) {
    	if (sum > n) return;
        if (path.size() == k) {
            if (sum == n) result.push_back(path);
            return;
        }
        for (int i = startIndex; i <= 9 - (k - path.size()) + 1; i++) {
            sum += i;
            path.push_back(i);
            traversal(n, k, sum, i + 1);
            sum -= i;
            path.pop_back();
        }

    }
    vector<vector<int>> combinationSum3(int k, int n) {
        traversal(n, k, 0, 1);
        return result;
    }
};

2 电话号码的字母组合

17.电话号码的字母组合
代码随想录刷题题Day21_第3张图片

(1)数字和字母如何映射
(2)用for循环写不出来
(3)输入1 * #按键等等异常情况

思路:

  1. 数字和字母如何映射
    使用map或者定义一个二维数组
const string[10] = {
	"", // 0
	"", // 1
	"abc", // 2
	"def", // 3
	"ghi", // 4
	"jkl", // 5
	"mno", // 6
	"pqrs",// 7
	"tuv", // 8
	"wxyz",// 9
};
  1. 回溯法来解决n个for循环的问题
    代码随想录刷题题Day21_第4张图片
    (1)确定回溯函数参数
    参数:digits,index(记录遍历第几个数字)
vector<string> result;
string s;
void backtracking(const string& digits, int index)

(2)确定终止条件

if (index == digits.size()) {
	result.push_back(s);
	return;
}

(3)确定单层遍历逻辑
1)首先要取index指向的数字,并找到对应的字符集。
2)然后for循环来处理这个字符集

int digit = digits[index] - '0';
string letters = letterMap[digit];
for (int i = 0; i < letter.size(); i++) {
	s.push_back(letters[i]);
	backtracking(digits, index + 1);
	s.pop_back();
}

C++:

class Solution {
public:
	const string letterMap[10] = {
		"", // 0
		"", // 1
		"abc", // 2
		"def", // 3
		"ghi", // 4
		"jkl", // 5
		"mno", // 6
		"pqrs",// 7
		"tuv", // 8
		"wxyz" // 9
	};
	string s;
	vector<string> result;
	void backtracking(const string& digits, int index)
	{
		if (index == digits.size()) {
			result.push_back(s);
			return;
		}
		int digit = digits[index] - '0';// 将index指向的数字转为int
		string letters = letterMap[digit];// 取数字对应的字符集
		for (int i = 0; i < letters.size(); i++) {
			s.push_back(letters[i]);// 处理
			backtracking(digits, index + 1); // 递归,注意index+1,一下层要处理下一个数字
			s.pop_back();// 回溯
		}
	}
    vector<string> letterCombinations(string digits) {
		s.clear();
		result.clear();
		if (digits.size() == 0) return result;
		backtracking(digits, 0);
		return result;
    }
};

时间复杂度: O ( 3 m ∗ 4 n ) O(3^m * 4^n) O(3m4n)

m 是对应四个字母的数字个数,n 是对应三个字母的数字个数

空间复杂度: O ( 3 m ∗ 4 n ) O(3^m * 4^n) O(3m4n)


鼓励坚持二十二天的自己

你可能感兴趣的:(代码随想录刷题,c++,数据结构,代码随想录,C++,回溯)