This commit is contained in:
youngyangyang04
2020-08-21 10:31:54 +08:00
parent 0c0bc10845
commit c35d55cf4e
9 changed files with 390 additions and 6 deletions

View File

@ -1,17 +1,67 @@
## 题目地址
# 题目地址
https://leetcode-cn.com/problems/two-sum/
## 思路
> 只用数组和set还是不够的
# 第1题. 两数之和
给定一个整数数组 nums 和一个目标值 target请你在该数组中找出和为目标值的那 两个 整数并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
**示例:**
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
# 思路
很明显暴力的解法是两层for循环查找时间复杂度是O(n^2)。
我们来看一下使用数组和set来做哈希法的局限。
使用哈希法最为合适之前已经介绍过数组和set在哈希法中的应用那么来看一下使用数组和set来做哈希法的局限。
* 数组的大小是受限制的,而且如果元素很少,而哈希值太大会造成内存空间的浪费。
* set是一个集合里面放的元素只能是一个key而两数之和这道题目不仅要判断y是否存在而且还要记录y的下表位置因为我们要返回x 和 y的下表。所以set 也不能用。
* set是一个集合里面放的元素只能是一个key而两数之和这道题目不仅要判断y是否存在而且还要记录y的下表位置因为要返回x 和 y的下表。所以set 也不能用。
此时我们就要选择一种数据结构 map map是一种key value的存储结构我们可以用key保存数值用value在保存数值所在的下表。
这道题目是map在哈希法中的经典应用
此时就要选择一种数据结构map map是一种key value的存储结构可以用key保存数值用value在保存数值所在的下表。
C++中map有三种类型
|映射 |底层实现 | 是否有序 |数值是否可以重复 | 能否更改数值|查询效率 |增删效率|
|---|---| --- |---| --- | --- | ---|
|std::map |红黑树 |key有序 |key不可重复 |key不可修改 | O(logn)|O(logn) |
|std::multimap | 红黑树|key有序 | key可重复 | key不可修改|O(logn) |O(logn) |
|std::unordered_map |哈希表 | key无序 |key不可重复 |key不可修改 |O(1) | O(1)|
std::unordered_map 底层实现为哈希表std::map 和std::multimap 的底层实现是红黑树。
同理std::map 和std::multimap 的key也是有序的这个问题也经常作为面试题考察对语言容器底层的理解。 更多哈希表的理论知识请看[关于哈希表,你该了解这些!](https://mp.weixin.qq.com/s/g8N6WmoQmsCUw3_BaWxHZA)。
**这道题目中并不需要key有序选择std::unordered_map 效率更高!**
# C++代码
```
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
std::unordered_map <int,int> map;
for(int i = 0; i < nums.size(); i++) {
auto iter = map.find(target - nums[i]);
if(iter != map.end()) {
return {iter->second, i};
break;
}
map.insert(nums[i], i);
}
return {};
}
};
```
## 一般解法

View File

@ -0,0 +1,66 @@
# 第39题. 组合总和
给定一个无重复元素的数组 candidates 和一个目标数 target 找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的数字可以无限制重复被选取。
**说明:**
所有数字包括 target都是正整数。
解集不能包含重复的组合。 
示例 1
输入candidates = [2,3,6,7], target = 7,
所求解集为:
[
[7],
[2,2,3]
]
示例 2
输入candidates = [2,3,5], target = 8,
所求解集为:
[
  [2,2,2,2],
  [2,3,3],
  [3,5]
]
# 思路
# C++代码
```
// 无限制重复被选取。 吓得我赶紧想想 0 可咋办
class Solution {
private:
vector<vector<int>> result;
void backtracking(vector<int>& candidates, int target, vector<int>& vec, int sum, int startIndex) {
if (sum > target) {
return;
}
if (sum == target) {
result.push_back(vec);
return;
}
// 因为可重复所以我们从0开始 这道题目感觉像是47.全排列II其实不是
for (int i = startIndex; i < candidates.size(); i++) {
sum += candidates[i];
vec.push_back(candidates[i]);
backtracking(candidates, target, vec, sum, i); // 关键点在这里不用i+1了
sum -= candidates[i];
vec.pop_back();
}
}
public:
vector<vector<int>> combinationSum(vector<int>& candidates, int target) {
vector<int> vec;
backtracking(candidates, target, vec, 0, 0);
return result;
}
};
```

View File

@ -0,0 +1,74 @@
# 第40题. 组合总和
给定一个数组 candidates 和一个目标数 target 找出 candidates 中所有可以使数字和为 target 的组合。
candidates 中的每个数字在每个组合中只能使用一次。
说明:
所有数字(包括目标数)都是正整数。
解集不能包含重复的组合。 
示例 1:
输入: candidates = [10,1,2,7,6,1,5], target = 8,
所求解集为:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
示例 2:
输入: candidates = [2,5,2,1,2], target = 5,
所求解集为:
[
  [1,2,2],
  [5]
]
# 思想
# C++代码
```
class Solution {
private:
vector<vector<int>> result;
void backtracking(vector<int>& candidates, int target, vector<int>& vec, int sum, int startIndex, vector<bool>& used) {
if (sum > target) {
return;
}
if (sum == target) {
result.push_back(vec);
return;
}
// 每个组合中只能使用一次 所以用 startindex
// 给定一个数组 candidates 默认有重复项,解集不能包含重复的组合。 所以使用if这一套
for (int i = startIndex; i < candidates.size(); i++) {
if (i > 0 && candidates[i] == candidates[i - 1] && used[i - 1] == false) {
continue;
}
sum += candidates[i];
vec.push_back(candidates[i]);
used[i] = true;
backtracking(candidates, target, vec, sum, i + 1, used); // 关键点在这里不用i+1了
used[i] = false;
sum -= candidates[i];
vec.pop_back();
}
}
public:
vector<vector<int>> combinationSum2(vector<int>& candidates, int target) {
vector<int> vec;
vector<bool> used(candidates.size(), false);
sort(candidates.begin(), candidates.end());
backtracking(candidates, target, vec, 0, 0, used);
return result;
}
};
```

46
problems/0077.组合.md Normal file
View File

@ -0,0 +1,46 @@
# 第77题. 组合
给定两个整数 n 和 k返回 1 ... n 中所有可能的 k 个数的组合。
示例:
输入: n = 4, k = 2
输出:
[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]
# 思路
# C++ 代码
```
class Solution {
private:
vector<vector<int>> result;
void backtracking(int n, int k, vector<int>& vec, int startIndex) {
if (vec.size() == k) {
result.push_back(vec);
return;
}
// 这个for循环有讲究组合的时候 要用startIndex排列的时候就要从0开始
// 这个过程好难理解,需要画图
for (int i = startIndex; i <= n; i++) {
vec.push_back(i);
backtracking(n, k, vec, i + 1);
vec.pop_back();
}
}
public:
vector<vector<int>> combine(int n, int k) {
vector<int> vec;
backtracking(n, k, vec, 1);
return result;
}
};
```

49
problems/0078.子集.md Normal file
View File

@ -0,0 +1,49 @@
# 题目地址
# 第78题. 子集
给定一组不含重复元素的整数数组 nums返回该数组所有可能的子集幂集
说明:解集不能包含重复的子集。
示例:
输入: nums = [1,2,3]
输出:
[
[3],
  [1],
  [2],
  [1,2,3],
  [1,3],
  [2,3],
  [1,2],
  []
]
# 思路
# C++代码
```
class Solution {
private:
void backtracking(vector<int>& nums, vector<vector<int>>& result, vector<int>& vec, int startIndex) {
result.push_back(vec);
for (int i = startIndex; i < nums.size(); i++) {
vec.push_back(nums[i]);
backtracking(nums, result, vec, i + 1);
vec.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> result;
vector<int> vec;
backtracking(nums, result, vec, 0);
return result;
}
};
```

38
problems/0090.子集II.md Normal file
View File

@ -0,0 +1,38 @@
# 题目地址
https://leetcode-cn.com/problems/subsets-ii/
# 第90题. 子集II
# 思路
# C++代码
```
class Solution {
private:
void backtracking(vector<int>& nums, vector<vector<int>>& result, vector<int>& vec, int startIndex, vector<bool>& used) {
result.push_back(vec);
for (int i = startIndex; i < nums.size(); i++) {
if (i > 0 && nums[i] == nums[i - 1] && used[i-1] == false) { // 果然去重都是一个逻辑啊
continue;
}
vec.push_back(nums[i]);
used[i] = true;
backtracking(nums, result, vec, i + 1, used);
used[i] = false;
vec.pop_back();
}
}
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<bool> used(nums.size(), false);
vector<vector<int>> result;
vector<int> vec;
sort(nums.begin(), nums.end());
backtracking(nums, result, vec, 0, used);
return result;
}
};
```

View File

@ -0,0 +1,56 @@
# 第216题. 组合总和 III
找出所有相加之和为 n 的 k 个数的组合。组合中只允许含有 1 - 9 的正整数,并且每种组合中不存在重复的数字。
说明:
所有数字都是正整数。
解集不能包含重复的组合。 
示例 1:
输入: k = 3, n = 7
输出: [[1,2,4]]
示例 2:
输入: k = 3, n = 9
输出: [[1,2,6], [1,3,5], [2,3,4]]
# 思路
# C++代码
```
class Solution {
private:
vector<vector<int>> result;
void backtracking(int target, int k, vector<int>& vec, int num, int sum, int startIndex) {
if (sum > target || num > k) {
return;
}
if (num == k && sum == target) {
result.push_back(vec);
return;
}
for (int i = startIndex; i <= 9; i++) {
sum += i;
vec.push_back(i);
num++;
backtracking(target, k, vec, num, sum, i + 1);
num--;
sum -= i;
vec.pop_back();
}
}
public:
vector<vector<int>> combinationSum3(int k, int n) {
vector<int> vec;
backtracking(n, k, vec, 0, 0, 1);
return result;
}
};
```