目录
一、基础
1.1 递归状态树
1.2 分治代码模板
分治代码与递归代码模板的区别:多了一步将结果合并(merge)
int divide_conquer(Problem* problem, int params) {
// recursion terminator
if (problem == nullptr) {
process_result
return return_result;
}
// process current problem
subproblems = split_problem(problem, data)
subresult1 = divide_conquer(subproblem[0], p1)
subresult2 = divide_conquer(subproblem[1], p1)
......
// merge
result = process_result(subresult1, subresult2, subresult3)
// revert the current level status
return 0;
}
1.3 复习递归代码模板
// C/C++
void recursion(int level, int param) {
// recursion terminator
if (level > MAX_LEVEL) {
// process result
return ;
}
// process current logic
process(level, param);
// drill down
recursion(level + 1, param);
// reverse the current level status if needed
}
1.4 回溯的概念
回溯法采用试错的思想,它尝试分步的去解决一个问题。
在分步解决问题的过程中,当它通过尝试发现现有的分步答案不能得到有效的正确的解答的时候,它将取消上一步甚至是上几步的计算,再通过其它的可能的分步解答再次尝试寻找问题的答案。
回溯法通常用最简单的递归方法来实现,在反复重复上述的步骤后可能出现两种情况:
- 找到一个可能存在的正确的答案;
- 在尝试了所有可能的分步方法后宣告该问题没有答案。
在最坏的情况下,回溯法会导致次复杂度为指数时间的计算。
二、实战习题
2.1 Pow(x, n)
实现 pow(x, n) ,即计算 x 的 n 次幂函数(即,xn)。
示例 1:
输入:x = 2.00000, n = 10
输出:1024.00000
示例 2:
输入:x = 2.10000, n = 3
输出:9.26100
示例 3:
输入:x = 2.00000, n = -2
输出:0.25000
解释:2-2 = 1/22 = 1/4 = 0.25
思路
拿到面试题后,先与面试官明确题意,数据边界。比如n是否可以为0,是否可以为负数,n的取值范围是多少等。
可以使用分而治之的思路进行求解。
class Solution {
public double myPow(double x, int n) {
double res = 1.0;
for(int i = n; i != 0; i /= 2){
if(i % 2 != 0){
res *= x;
}
x *= x;
}
return n < 0 ? 1 / res : res;
}
}
2.2 子集
给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
示例 1:
输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
示例 2:
输入:nums = [0]
输出:[[],[0]]
提示:
- 1 <= nums.length <= 10
- -10 <= nums[i] <= 10
- nums 中的所有元素 互不相同
思路:
观察一下数组nums。可以得出如下规律
nums长度 | 排列组合结果 | 元素个数 |
0 | [] | 1 |
1 | [] [1] | 2 |
2 | [] [1] [2] [1,2] | 4 |
3 | [] [1] [2] [1,2] [3] [1,3] [2,3] [1,2,3] | 8 |
nums中每增加一个元素,子集的个数 = 增加元素之前的子集 + 新增元素与旧子集中每个元素进行组合
因此可以得出如下答案:
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>>res;
vector<int>temp;
res.push_back(temp);
//有几个元素就会有2的n次幂的结果
for(auto i : nums){
int size = res.size();
for(int j=0; j< size;j++){
temp = res[j];
temp.push_back(i);
res.push_back(temp);
}
}
return res;
}
};
一遍ac,舒服~
三、实战题目
- https://leetcode-cn.com/problems/majority-element/description/ (简单、但是高频)
- https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number/
- https://leetcode-cn.com/problems/n-queens/
3.1 多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:
输入:[2,2,1,1,1,2,2]
输出:2
进阶:
- 尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
思路:
超过半数的那个数的个数一定大于数组长度的一半(这不是废话吗)。所以,用两个变量res和time,res代表当前出现次数最多的数,time记录该数出现的次数。遍历数组
- 如果当前元素与res的数值不同,则将time-1;
- 若相同,则time+1
- 若不同,time<=0,说明当前res记录的数并非是我们想要的结果。此时将当前遍历的值作为出现次数最多的数,并更新time的值为1;
从而有如下答案:
class Solution {
public:
int majorityElement(vector<int>& nums) {
int res=nums[0];
int time=1;
for(int i=0; i<nums.size();i++){
if(nums[i]!= res){
time--;
if(time<=0){
res=nums[i];
time=1;
}
}else{
time++;
}
}
return res;
}
};
3.2 电话号码的字母组合
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:
输入:digits = ""
输出:[]
示例 3:
输入:digits = "2"
输出:["a","b","c"]
提示:
0 <= digits.length <= 4
digits[i]
是范围['2', '9']
的一个数字。
class Solution {
public:
const vector<string> keyboard{"", "", "abc", "def", // '0','1','2',...
"ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" };
vector<string> letterCombinations (const string &digits) {
vector<string> result;
if (digits == "") return result;
dfs(digits, 0, "", result);
return result;
}
void dfs(const string &digits, size_t cur, string path,
vector<string> &result) {
if (cur == digits.size()) {
result.push_back(path);
return;
}
for (auto c : keyboard[digits[cur] - '0']) {
dfs(digits, cur + 1, path + c, result);
}
}
};
3.3 N 皇后
n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上,并且使皇后彼此之间不能相互攻击。
给你一个整数 n ,返回所有不同的 n 皇后问题 的解决方案。
每一种解法包含一个不同的 n 皇后问题 的棋子放置方案,该方案中 'Q' 和 '.' 分别代表了皇后和空位。
输入:n = 4
输出:[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
解释:如上图所示,4 皇后问题存在两个不同的解法。
难题,先放放。。。。脑瓜疼
扩展阅读:
牛顿迭代法——http://www.matrix67.com/blog/archives/361