mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-06 23:28:29 +08:00
Update
This commit is contained in:
@ -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 {};
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
## 一般解法
|
||||
|
||||
|
66
problems/0039.组合总和.md
Normal file
66
problems/0039.组合总和.md
Normal 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;
|
||||
}
|
||||
};
|
||||
```
|
74
problems/0040.组合总和II.md
Normal file
74
problems/0040.组合总和II.md
Normal 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
46
problems/0077.组合.md
Normal 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
49
problems/0078.子集.md
Normal 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
38
problems/0090.子集II.md
Normal 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;
|
||||
}
|
||||
};
|
||||
```
|
56
problems/0216.组合总和III.md
Normal file
56
problems/0216.组合总和III.md
Normal 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;
|
||||
|
||||
}
|
||||
};
|
||||
```
|
Reference in New Issue
Block a user