mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-08 16:54:50 +08:00
Merge branch 'youngyangyang04:master' into master
This commit is contained in:
@ -207,18 +207,16 @@ function twoSum(array $nums, int $target): array
|
|||||||
Swift:
|
Swift:
|
||||||
```swift
|
```swift
|
||||||
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
|
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
|
||||||
var res = [Int]()
|
// 值: 下标
|
||||||
var dict = [Int : Int]()
|
var map = [Int: Int]()
|
||||||
for i in 0 ..< nums.count {
|
for (i, e) in nums.enumerated() {
|
||||||
let other = target - nums[i]
|
if let v = map[target - e] {
|
||||||
if dict.keys.contains(other) {
|
return [v, i]
|
||||||
res.append(i)
|
} else {
|
||||||
res.append(dict[other]!)
|
map[e] = i
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
dict[nums[i]] = i
|
|
||||||
}
|
}
|
||||||
return res
|
return []
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 到这里了说明整个数组都是倒叙了,反转一下便可
|
// 到这里了说明整个数组都是倒序了,反转一下便可
|
||||||
reverse(nums.begin(), nums.end());
|
reverse(nums.begin(), nums.end());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -323,5 +323,76 @@ func permuteUnique(_ nums: [Int]) -> [[Int]] {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### C
|
||||||
|
```c
|
||||||
|
//临时数组
|
||||||
|
int *path;
|
||||||
|
//返回数组
|
||||||
|
int **ans;
|
||||||
|
int *used;
|
||||||
|
int pathTop, ansTop;
|
||||||
|
|
||||||
|
//拷贝path到ans中
|
||||||
|
void copyPath() {
|
||||||
|
int *tempPath = (int*)malloc(sizeof(int) * pathTop);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < pathTop; ++i) {
|
||||||
|
tempPath[i] = path[i];
|
||||||
|
}
|
||||||
|
ans[ansTop++] = tempPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
void backTracking(int* used, int *nums, int numsSize) {
|
||||||
|
//若path中元素个数等于numsSize,将path拷贝入ans数组中
|
||||||
|
if(pathTop == numsSize)
|
||||||
|
copyPath();
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < numsSize; i++) {
|
||||||
|
//若当前元素已被使用
|
||||||
|
//或前一位元素与当前元素值相同但并未被使用
|
||||||
|
//则跳过此分支
|
||||||
|
if(used[i] || (i != 0 && nums[i] == nums[i-1] && used[i-1] == 0))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//将当前元素的使用情况设为True
|
||||||
|
used[i] = 1;
|
||||||
|
path[pathTop++] = nums[i];
|
||||||
|
backTracking(used, nums, numsSize);
|
||||||
|
used[i] = 0;
|
||||||
|
--pathTop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmp(void* elem1, void* elem2) {
|
||||||
|
return *((int*)elem1) - *((int*)elem2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int** permuteUnique(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
|
||||||
|
//排序数组
|
||||||
|
qsort(nums, numsSize, sizeof(int), cmp);
|
||||||
|
//初始化辅助变量
|
||||||
|
pathTop = ansTop = 0;
|
||||||
|
path = (int*)malloc(sizeof(int) * numsSize);
|
||||||
|
ans = (int**)malloc(sizeof(int*) * 1000);
|
||||||
|
//初始化used辅助数组
|
||||||
|
used = (int*)malloc(sizeof(int) * numsSize);
|
||||||
|
int i;
|
||||||
|
for(i = 0; i < numsSize; i++) {
|
||||||
|
used[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
backTracking(used, nums, numsSize);
|
||||||
|
|
||||||
|
//设置返回的数组的长度
|
||||||
|
*returnSize = ansTop;
|
||||||
|
*returnColumnSizes = (int*)malloc(sizeof(int) * ansTop);
|
||||||
|
int z;
|
||||||
|
for(z = 0; z < ansTop; z++) {
|
||||||
|
(*returnColumnSizes)[z] = numsSize;
|
||||||
|
}
|
||||||
|
return ans;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
-----------------------
|
-----------------------
|
||||||
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
|
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
|
||||||
|
|
||||||
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒叙了,那么再把单词反转一下,单词不就正过来了。
|
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。
|
||||||
|
|
||||||
所以解题思路如下:
|
所以解题思路如下:
|
||||||
|
|
||||||
|
@ -101,7 +101,6 @@ s[j] = tmp;
|
|||||||
s[i] ^= s[j];
|
s[i] ^= s[j];
|
||||||
s[j] ^= s[i];
|
s[j] ^= s[i];
|
||||||
s[i] ^= s[j];
|
s[i] ^= s[j];
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
这道题目还是比较简单的,但是我正好可以通过这道题目说一说在刷题的时候,使用库函数的原则。
|
这道题目还是比较简单的,但是我正好可以通过这道题目说一说在刷题的时候,使用库函数的原则。
|
||||||
|
@ -107,7 +107,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
|
// 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
|
||||||
vector<int> result(k);
|
vector<int> result(k);
|
||||||
for (int i = k - 1; i >= 0; i--) {
|
for (int i = k - 1; i >= 0; i--) {
|
||||||
result[i] = pri_que.top().first;
|
result[i] = pri_que.top().first;
|
||||||
@ -180,7 +180,7 @@ class Solution:
|
|||||||
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
|
if len(pri_que) > k: #如果堆的大小大于了K,则队列弹出,保证堆的大小一直为k
|
||||||
heapq.heappop(pri_que)
|
heapq.heappop(pri_que)
|
||||||
|
|
||||||
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组
|
#找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组
|
||||||
result = [0] * k
|
result = [0] * k
|
||||||
for i in range(k-1, -1, -1):
|
for i in range(k-1, -1, -1):
|
||||||
result[i] = heapq.heappop(pri_que)[1]
|
result[i] = heapq.heappop(pri_que)[1]
|
||||||
|
@ -112,7 +112,7 @@ vector<int> dp(10001, 0);
|
|||||||
|
|
||||||
4. 确定遍历顺序
|
4. 确定遍历顺序
|
||||||
|
|
||||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
|
@ -44,7 +44,7 @@ D = [ 0, 2]
|
|||||||
|
|
||||||
1. 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
|
1. 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数。
|
||||||
2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
|
2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
|
||||||
3. 定义int变量count,用来统计a+b+c+d = 0 出现的次数。
|
3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
|
||||||
4. 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
|
4. 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
|
||||||
5. 最后返回统计值 count 就可以了
|
5. 最后返回统计值 count 就可以了
|
||||||
|
|
||||||
@ -139,7 +139,7 @@ class Solution(object):
|
|||||||
return count
|
return count
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Go:
|
Go:
|
||||||
```go
|
```go
|
||||||
@ -229,28 +229,24 @@ class Solution {
|
|||||||
Swift:
|
Swift:
|
||||||
```swift
|
```swift
|
||||||
func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int {
|
func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int {
|
||||||
// key:a+b的数值,value:a+b数值出现的次数
|
// ab和: ab和出现次数
|
||||||
var map = [Int: Int]()
|
var countDic = [Int: Int]()
|
||||||
// 遍历nums1和nums2数组,统计两个数组元素之和,和出现的次数,放到map中
|
for a in nums1 {
|
||||||
for i in 0 ..< nums1.count {
|
for b in nums2 {
|
||||||
for j in 0 ..< nums2.count {
|
let key = a + b
|
||||||
let sum1 = nums1[i] + nums2[j]
|
countDic[key] = countDic[key, default: 0] + 1
|
||||||
map[sum1] = (map[sum1] ?? 0) + 1
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 统计a+b+c+d = 0 出现的次数
|
|
||||||
var res = 0
|
// 通过-(c + d)作为key,去累加ab和出现的次数
|
||||||
// 在遍历大num3和num4数组,找到如果 0-(c+d) 在map中出现过的话,就把map中key对应的value也就是出现次数统计出来。
|
var result = 0
|
||||||
for i in 0 ..< nums3.count {
|
for c in nums3 {
|
||||||
for j in 0 ..< nums4.count {
|
for d in nums4 {
|
||||||
let sum2 = nums3[i] + nums4[j]
|
let key = -(c + d)
|
||||||
let other = 0 - sum2
|
result += countDic[key, default: 0]
|
||||||
if map.keys.contains(other) {
|
|
||||||
res += map[other]!
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res
|
return result
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ for (int i = 0; i < n; i++) {
|
|||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
vector<int> vec; // 记录入度为2的边(如果有的话就两条边)
|
||||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||||
for (int i = n - 1; i >= 0; i--) {
|
for (int i = n - 1; i >= 0; i--) {
|
||||||
if (inDegree[edges[i][1]] == 2) {
|
if (inDegree[edges[i][1]] == 2) {
|
||||||
vec.push_back(i);
|
vec.push_back(i);
|
||||||
@ -577,7 +577,7 @@ var findRedundantDirectedConnection = function(edges) {
|
|||||||
inDegree[edges[i][1]]++; // 统计入度
|
inDegree[edges[i][1]]++; // 统计入度
|
||||||
}
|
}
|
||||||
let vec = [];// 记录入度为2的边(如果有的话就两条边)
|
let vec = [];// 记录入度为2的边(如果有的话就两条边)
|
||||||
// 找入度为2的节点所对应的边,注意要倒叙,因为优先返回最后出现在二维数组中的答案
|
// 找入度为2的节点所对应的边,注意要倒序,因为优先返回最后出现在二维数组中的答案
|
||||||
for (let i = n - 1; i >= 0; i--) {
|
for (let i = n - 1; i >= 0; i--) {
|
||||||
if (inDegree[edges[i][1]] == 2) {
|
if (inDegree[edges[i][1]] == 2) {
|
||||||
vec.push(i);
|
vec.push(i);
|
||||||
|
@ -82,7 +82,7 @@ dp[1] = cost[1];
|
|||||||
|
|
||||||
**但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来**。
|
**但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来**。
|
||||||
|
|
||||||
例如:01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒叙呢?
|
例如:01背包,都知道两个for循环,一个for遍历物品嵌套一个for遍历背包容量,那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢? 以及在使用一维dp数组的时候遍历背包容量为什么要倒序呢?
|
||||||
|
|
||||||
**这些都是遍历顺序息息相关。当然背包问题后续「代码随想录」都会重点讲解的!**
|
**这些都是遍历顺序息息相关。当然背包问题后续「代码随想录」都会重点讲解的!**
|
||||||
|
|
||||||
|
@ -58,7 +58,7 @@ words[i] 由小写英文字母组成
|
|||||||
|
|
||||||
先统计第一个字符串所有字符出现的次数,代码如下:
|
先统计第一个字符串所有字符出现的次数,代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
|
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
|
||||||
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
||||||
hash[A[0][i] - 'a']++;
|
hash[A[0][i] - 'a']++;
|
||||||
@ -71,7 +71,7 @@ for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
|
|||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
|
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
|
||||||
for (int i = 1; i < A.size(); i++) {
|
for (int i = 1; i < A.size(); i++) {
|
||||||
memset(hashOtherStr, 0, 26 * sizeof(int));
|
memset(hashOtherStr, 0, 26 * sizeof(int));
|
||||||
@ -84,11 +84,11 @@ for (int i = 1; i < A.size(); i++) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
此时hash里统计着字符在所有字符串里出现的最小次数,那么把hash转正题目要求的输出格式就可以了。
|
此时hash里统计着字符在所有字符串里出现的最小次数,那么把hash转成题目要求的输出格式就可以了。
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
```
|
```cpp
|
||||||
// 将hash统计的字符次数,转成输出形式
|
// 将hash统计的字符次数,转成输出形式
|
||||||
for (int i = 0; i < 26; i++) {
|
for (int i = 0; i < 26; i++) {
|
||||||
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
while (hash[i] != 0) { // 注意这里是while,多个重复的字符
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒叙的,所以在对字符串进行反转一下,就得到了最终的结果。
|
从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒序的,所以在对字符串进行反转一下,就得到了最终的结果。
|
||||||
|
|
||||||
C++代码 :
|
C++代码 :
|
||||||
|
|
||||||
|
@ -87,7 +87,7 @@ vector<int> dp(15001, 0);
|
|||||||
4. 确定遍历顺序
|
4. 确定遍历顺序
|
||||||
|
|
||||||
|
|
||||||
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒叙遍历!
|
在[动态规划:关于01背包问题,你该了解这些!(滚动数组)](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明:如果使用一维dp数组,物品遍历的for循环放在外层,遍历背包的for循环放在内层,且内层for循环倒序遍历!
|
||||||
|
|
||||||
代码如下:
|
代码如下:
|
||||||
|
|
||||||
|
@ -103,7 +103,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
|
|||||||
|
|
||||||
为什么呢?
|
为什么呢?
|
||||||
|
|
||||||
**倒叙遍历是为了保证物品i只被放入一次!**。但如果一旦正序遍历了,那么物品0就会被重复加入多次!
|
**倒序遍历是为了保证物品i只被放入一次!**。但如果一旦正序遍历了,那么物品0就会被重复加入多次!
|
||||||
|
|
||||||
举一个例子:物品0的重量weight[0] = 1,价值value[0] = 15
|
举一个例子:物品0的重量weight[0] = 1,价值value[0] = 15
|
||||||
|
|
||||||
@ -115,9 +115,9 @@ dp[2] = dp[2 - weight[0]] + value[0] = 30
|
|||||||
|
|
||||||
此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。
|
此时dp[2]就已经是30了,意味着物品0,被放入了两次,所以不能正序遍历。
|
||||||
|
|
||||||
为什么倒叙遍历,就可以保证物品只放入一次呢?
|
为什么倒序遍历,就可以保证物品只放入一次呢?
|
||||||
|
|
||||||
倒叙就是先算dp[2]
|
倒序就是先算dp[2]
|
||||||
|
|
||||||
dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)
|
dp[2] = dp[2 - weight[0]] + value[0] = 15 (dp数组已经都初始化为0)
|
||||||
|
|
||||||
@ -125,7 +125,7 @@ dp[1] = dp[1 - weight[0]] + value[0] = 15
|
|||||||
|
|
||||||
所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。
|
所以从后往前循环,每次取得状态不会和之前取得状态重合,这样每种物品就只取一次了。
|
||||||
|
|
||||||
**那么问题又来了,为什么二维dp数组历的时候不用倒叙呢?**
|
**那么问题又来了,为什么二维dp数组历的时候不用倒序呢?**
|
||||||
|
|
||||||
因为对于二维dp,dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖!
|
因为对于二维dp,dp[i][j]都是通过上一层即dp[i - 1][j]计算而来,本层的dp[i][j]并不会被覆盖!
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user