Merge branch 'youngyangyang04:master' into master

This commit is contained in:
Wayne
2022-02-12 14:36:53 +08:00
committed by GitHub
85 changed files with 3750 additions and 402 deletions

View File

@ -5,10 +5,11 @@
> 1. **介绍**:本项目是一套完整的刷题计划,旨在帮助大家少走弯路,循序渐进学算法,[关注作者](#关于作者)
> 2. **PDF版本** [「代码随想录」算法精讲 PDF 版本](https://programmercarl.com/other/algo_pdf.html) 。
> 3. **刷题顺序** README已经将刷题顺序排好了按照顺序一道一道刷就可以。
> 4. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html)
> 5. **提交代码**本项目统一使用C++语言进行讲解但已经有Java、Python、Go、JavaScript等等多语言版本感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式
> 6. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
> 3. **最强八股文:**[代码随想录知识星球精华PDF](https://www.programmercarl.com/other/kstar_baguwen.html)
> 4. **刷题顺序** README已经将刷题顺序排好了按照顺序一道一道刷就可以
> 5. **学习社区** : 一起学习打卡/面试技巧/如何选择offer/大厂内推/职场规则/简历修改/技术分享/程序人生。欢迎加入[「代码随想录」知识星球](https://programmercarl.com/other/kstar.html)
> 6. **提交代码**本项目统一使用C++语言进行讲解但已经有Java、Python、Go、JavaScript等等多语言版本感谢[这里的每一位贡献者](https://github.com/youngyangyang04/leetcode-master/graphs/contributors),如果你也想贡献代码点亮你的头像,[点击这里](https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A)了解提交代码的方式。
> 7. **转载须知** :以下所有文章皆为我([程序员Carl](https://github.com/youngyangyang04))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!
<p align="center">
<a href="programmercarl.com" target="_blank">

View File

@ -186,6 +186,24 @@ var twoSum = function (nums, target) {
};
```
TypeScript
```typescript
function twoSum(nums: number[], target: number): number[] {
let helperMap: Map<number, number> = new Map();
let index: number | undefined;
let resArr: number[] = [];
for (let i = 0, length = nums.length; i < length; i++) {
index = helperMap.get(target - nums[i]);
if (index !== undefined) {
resArr = [i, index];
}
helperMap.set(nums[i], i);
}
return resArr;
};
```
php
```php
@ -207,18 +225,16 @@ function twoSum(array $nums, int $target): array
Swift
```swift
func twoSum(_ nums: [Int], _ target: Int) -> [Int] {
var res = [Int]()
var dict = [Int : Int]()
for i in 0 ..< nums.count {
let other = target - nums[i]
if dict.keys.contains(other) {
res.append(i)
res.append(dict[other]!)
return res
// 值: 下标
var map = [Int: Int]()
for (i, e) in nums.enumerated() {
if let v = map[target - e] {
return [v, i]
} else {
map[e] = i
}
dict[nums[i]] = i
}
return res
return []
}
```

View File

@ -462,7 +462,92 @@ var longestPalindrome = function(s) {
};
```
## C
动态规划:
```c
//初始化dp数组全部初始为false
bool **initDP(int strLen) {
bool **dp = (bool **)malloc(sizeof(bool *) * strLen);
int i, j;
for(i = 0; i < strLen; ++i) {
dp[i] = (bool *)malloc(sizeof(bool) * strLen);
for(j = 0; j < strLen; ++j)
dp[i][j] = false;
}
return dp;
}
char * longestPalindrome(char * s){
//求出字符串长度
int strLen = strlen(s);
//初始化dp数组元素初始化为false
bool **dp = initDP(strLen);
int maxLength = 0, left = 0, right = 0;
//从下到上,从左到右遍历
int i, j;
for(i = strLen - 1; i >= 0; --i) {
for(j = i; j < strLen; ++j) {
//若当前i与j所指字符一样
if(s[i] == s[j]) {
//若i、j指向相邻字符或同一字符则为回文字符串
if(j - i <= 1)
dp[i][j] = true;
//若i+1与j-1所指字符串为回文字符串则i、j所指字符串为回文字符串
else if(dp[i + 1][j - 1])
dp[i][j] = true;
}
//若新的字符串的长度大于之前的最大长度,进行更新
if(dp[i][j] && j - i + 1 > maxLength) {
maxLength = j - i + 1;
left = i;
right = j;
}
}
}
//复制回文字符串,并返回
char *ret = (char*)malloc(sizeof(char) * (maxLength + 1));
memcpy(ret, s + left, maxLength);
ret[maxLength] = 0;
return ret;
}
```
双指针:
```c
int left, maxLength;
void extend(char *str, int i, int j, int size) {
while(i >= 0 && j < size && str[i] == str[j]) {
//若当前子字符串长度大于最长的字符串长度,进行更新
if(j - i + 1 > maxLength) {
maxLength = j - i + 1;
left = i;
}
//左指针左移,右指针右移。扩大搜索范围
++j, --i;
}
}
char * longestPalindrome(char * s){
left = right = maxLength = 0;
int size = strlen(s);
int i;
for(i = 0; i < size; ++i) {
//长度为单数的子字符串
extend(s, i, i, size);
//长度为双数的子字符串
extend(s, i, i + 1, size);
}
//复制子字符串
char *subStr = (char *)malloc(sizeof(char) * (maxLength + 1));
memcpy(subStr, s + left, maxLength);
subStr[maxLength] = 0;
return subStr;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -332,7 +332,43 @@ var threeSum = function(nums) {
return res;
};
```
TypeScript:
```typescript
function threeSum(nums: number[]): number[][] {
nums.sort((a, b) => a - b);
let length = nums.length;
let left: number = 0,
right: number = length - 1;
let resArr: number[][] = [];
for (let i = 0; i < length; i++) {
if (i > 0 && nums[i] === nums[i - 1]) {
continue;
}
left = i + 1;
right = length - 1;
while (left < right) {
let total: number = nums[i] + nums[left] + nums[right];
if (total === 0) {
resArr.push([nums[i], nums[left], nums[right]]);
left++;
right--;
while (nums[right] === nums[right + 1]) {
right--;
}
while (nums[left] === nums[left - 1]) {
left++;
}
} else if (total < 0) {
left++;
} else {
right--;
}
}
}
return resArr;
};
```
ruby:
```ruby
@ -509,5 +545,64 @@ int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes
}
```
C#:
```csharp
public class Solution
{
public IList<IList<int>> ThreeSum(int[] nums)
{
var result = new List<IList<int>>();
Array.Sort(nums);
for (int i = 0; i < nums.Length - 2; i++)
{
int n1 = nums[i];
if (n1 > 0)
break;
if (i > 0 && n1 == nums[i - 1])
continue;
int left = i + 1;
int right = nums.Length - 1;
while (left < right)
{
int n2 = nums[left];
int n3 = nums[right];
int sum = n1 + n2 + n3;
if (sum > 0)
{
right--;
}
else if (sum < 0)
{
left++;
}
else
{
result.Add(new List<int> { n1, n2, n3 });
while (left < right && nums[left] == n2)
{
left++;
}
while (left < right && nums[right] == n3)
{
right--;
}
}
}
}
return result;
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -311,7 +311,49 @@ var fourSum = function(nums, target) {
};
```
TypeScript
```typescript
function fourSum(nums: number[], target: number): number[][] {
nums.sort((a, b) => a - b);
let first: number = 0,
second: number,
third: number,
fourth: number;
let length: number = nums.length;
let resArr: number[][] = [];
for (; first < length; first++) {
if (first > 0 && nums[first] === nums[first - 1]) {
continue;
}
for (second = first + 1; second < length; second++) {
if ((second - first) > 1 && nums[second] === nums[second - 1]) {
continue;
}
third = second + 1;
fourth = length - 1;
while (third < fourth) {
let total: number = nums[first] + nums[second] + nums[third] + nums[fourth];
if (total === target) {
resArr.push([nums[first], nums[second], nums[third], nums[fourth]]);
third++;
fourth--;
while (nums[third] === nums[third - 1]) third++;
while (nums[fourth] === nums[fourth + 1]) fourth--;
} else if (total < target) {
third++;
} else {
fourth--;
}
}
}
}
return resArr;
};
```
PHP:
```php
class Solution {
/**
@ -403,5 +445,67 @@ func fourSum(_ nums: [Int], _ target: Int) -> [[Int]] {
}
```
C#:
```csharp
public class Solution
{
public IList<IList<int>> FourSum(int[] nums, int target)
{
var result = new List<IList<int>>();
Array.Sort(nums);
for (int i = 0; i < nums.Length - 3; i++)
{
int n1 = nums[i];
if (i > 0 && n1 == nums[i - 1])
continue;
for (int j = i + 1; j < nums.Length - 2; j++)
{
int n2 = nums[j];
if (j > i + 1 && n2 == nums[j - 1])
continue;
int left = j + 1;
int right = nums.Length - 1;
while (left < right)
{
int n3 = nums[left];
int n4 = nums[right];
int sum = n1 + n2 + n3 + n4;
if (sum > target)
{
right--;
}
else if (sum < target)
{
left++;
}
else
{
result.Add(new List<int> { n1, n2, n3, n4 });
while (left < right && nums[left] == n3)
{
left++;
}
while (left < right && nums[right] == n4)
{
right--;
}
}
}
}
}
return result;
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -181,7 +181,71 @@ var removeNthFromEnd = function(head, n) {
return ret.next;
};
```
TypeScript:
版本一(快慢指针法):
```typescript
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
let newHead: ListNode | null = new ListNode(0, head);
let slowNode: ListNode | null = newHead,
fastNode: ListNode | null = newHead;
for (let i = 0; i < n; i++) {
fastNode = fastNode.next;
}
while (fastNode.next) {
fastNode = fastNode.next;
slowNode = slowNode.next;
}
slowNode.next = slowNode.next.next;
return newHead.next;
};
```
版本二(计算节点总数法):
```typescript
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
let curNode: ListNode | null = head;
let listSize: number = 0;
while (curNode) {
curNode = curNode.next;
listSize++;
}
if (listSize === n) {
head = head.next;
} else {
curNode = head;
for (let i = 0; i < listSize - n - 1; i++) {
curNode = curNode.next;
}
curNode.next = curNode.next.next;
}
return head;
};
```
版本三递归倒退n法
```typescript
function removeNthFromEnd(head: ListNode | null, n: number): ListNode | null {
let newHead: ListNode | null = new ListNode(0, head);
let cnt = 0;
function recur(node) {
if (node === null) return;
recur(node.next);
cnt++;
if (cnt === n + 1) {
node.next = node.next.next;
}
}
recur(newHead);
return newHead.next;
};
```
Kotlin:
```Kotlin
fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? {
val pre = ListNode(0).apply {

View File

@ -283,8 +283,60 @@ var isValid = function(s) {
};
```
TypeScript:
版本一:普通版
```typescript
function isValid(s: string): boolean {
let helperStack: string[] = [];
for (let i = 0, length = s.length; i < length; i++) {
let x: string = s[i];
switch (x) {
case '(':
helperStack.push(')');
break;
case '[':
helperStack.push(']');
break;
case '{':
helperStack.push('}');
break;
default:
if (helperStack.pop() !== x) return false;
break;
}
}
return helperStack.length === 0;
};
```
版本二:优化版
```typescript
function isValid(s: string): boolean {
type BracketMap = {
[index: string]: string;
}
let helperStack: string[] = [];
let bracketMap: BracketMap = {
'(': ')',
'[': ']',
'{': '}'
}
for (let i of s) {
if (bracketMap.hasOwnProperty(i)) {
helperStack.push(bracketMap[i]);
} else if (i !== helperStack.pop()) {
return false;
}
}
return helperStack.length === 0;
};
```
Swift
```swift
func isValid(_ s: String) -> Bool {
var stack = [String.Element]()

View File

@ -250,6 +250,38 @@ var swapPairs = function (head) {
};
```
TypeScript
```typescript
function swapPairs(head: ListNode | null): ListNode | null {
/**
* 初始状态:
* curNode -> node1 -> node2 -> tmepNode
* 转换过程:
* curNode -> node2
* curNode -> node2 -> node1
* curNode -> node2 -> node1 -> tempNode
* curNode = node1
*/
let retNode: ListNode | null = new ListNode(0, head),
curNode: ListNode | null = retNode,
node1: ListNode | null = null,
node2: ListNode | null = null,
tempNode: ListNode | null = null;
while (curNode && curNode.next && curNode.next.next) {
node1 = curNode.next;
node2 = curNode.next.next;
tempNode = node2.next;
curNode.next = node2;
node2.next = node1;
node1.next = tempNode;
curNode = node1;
}
return retNode.next;
};
```
Kotlin:
```kotlin

View File

@ -42,7 +42,7 @@
![27.移除元素-暴力解法](https://tva1.sinaimg.cn/large/008eGmZEly1gntrc7x9tjg30du09m1ky.gif)
很明显暴力解法的时间复杂度是O(n^2)这道题目暴力解法在leetcode上是可以过的。
很明显暴力解法的时间复杂度是$O(n^2)$这道题目暴力解法在leetcode上是可以过的。
代码如下:

View File

@ -259,7 +259,7 @@ void getNext(int* next, const string& s)
然后还要对next数组进行初始化赋值如下
```
```cpp
int j = -1;
next[0] = j;
```
@ -278,8 +278,8 @@ next[i] 表示 i包括i之前最长相等的前后缀长度其实就是
所以遍历模式串s的循环下标i 要从 1开始代码如下
```
for(int i = 1; i < s.size(); i++) {
```cpp
for (int i = 1; i < s.size(); i++) {
```
如果 s[i] 与 s[j+1]不相同,也就是遇到 前后缀末尾不相同的情况,就要向前回退。
@ -292,7 +292,7 @@ next[j]就是记录着j包括j之前的子串的相同前后缀的长度
所以,处理前后缀不相同的情况代码如下:
```
```cpp
while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
    j = next[j]; // 向前回退
}
@ -300,7 +300,7 @@ while (j >= 0 && s[i] != s[j + 1]) { // 前后缀不相同了
3. 处理前后缀相同的情况
如果s[i] 与 s[j + 1] 相同那么就同时向后移动i 和j 说明找到了相同的前后缀同时还要将j前缀的长度赋给next[i], 因为next[i]要记录相同前后缀的长度。
如果 s[i] 与 s[j + 1] 相同那么就同时向后移动i 和j 说明找到了相同的前后缀同时还要将j前缀的长度赋给next[i], 因为next[i]要记录相同前后缀的长度。
代码如下:
@ -346,7 +346,7 @@ void getNext(int* next, const string& s){
i就从0开始遍历文本串代码如下
```
```cpp
for (int i = 0; i < s.size(); i++) 
```
@ -356,7 +356,7 @@ for (int i = 0; i < s.size(); i++) 
代码如下:
```
```cpp
while(j >= 0 && s[i] != t[j + 1]) {
    j = next[j];
}
@ -364,7 +364,7 @@ while(j >= 0 && s[i] != t[j + 1]) {
如果 s[i] 与 t[j + 1] 相同那么i 和 j 同时向后移动, 代码如下:
```
```cpp
if (s[i] == t[j + 1]) {
    j++; // i的增加在for循环里
}
@ -376,7 +376,7 @@ if (s[i] == t[j + 1]) {
代码如下:
```
```cpp
if (j == (t.size() - 1) ) {
    return (i - t.size() + 1);
}
@ -929,6 +929,83 @@ var strStr = function (haystack, needle) {
};
```
TypeScript版本
> 前缀表统一减一
```typescript
function strStr(haystack: string, needle: string): number {
function getNext(str: string): number[] {
let next: number[] = [];
let j: number = -1;
next[0] = j;
for (let i = 1, length = str.length; i < length; i++) {
while (j >= 0 && str[i] !== str[j + 1]) {
j = next[j];
}
if (str[i] === str[j + 1]) {
j++;
}
next[i] = j;
}
return next;
}
if (needle.length === 0) return 0;
let next: number[] = getNext(needle);
let j: number = -1;
for (let i = 0, length = haystack.length; i < length; i++) {
while (j >= 0 && haystack[i] !== needle[j + 1]) {
j = next[j];
}
if (haystack[i] === needle[j + 1]) {
if (j === needle.length - 2) {
return i - j - 1;
}
j++;
}
}
return -1;
};
```
> 前缀表不减一
```typescript
// 不减一版本
function strStr(haystack: string, needle: string): number {
function getNext(str: string): number[] {
let next: number[] = [];
let j: number = 0;
next[0] = j;
for (let i = 1, length = str.length; i < length; i++) {
while (j > 0 && str[i] !== str[j]) {
j = next[j - 1];
}
if (str[i] === str[j]) {
j++;
}
next[i] = j;
}
return next;
}
if (needle.length === 0) return 0;
let next: number[] = getNext(needle);
let j: number = 0;
for (let i = 0, length = haystack.length; i < length; i++) {
while (j > 0 && haystack[i] !== needle[j]) {
j = next[j - 1];
}
if (haystack[i] === needle[j]) {
if (j === needle.length - 1) {
return i - j;
}
j++;
}
}
return -1;
}
```
Swift 版本
> 前缀表统一减一

View File

@ -81,12 +81,12 @@ public:
for (int j = nums.size() - 1; j > i; j--) {
if (nums[j] > nums[i]) {
swap(nums[j], nums[i]);
sort(nums.begin() + i + 1, nums.end());
reverse(nums.begin() + i + 1, nums.end());
return;
}
}
}
// 到这里了说明整个数组都是倒了,反转一下便可
// 到这里了说明整个数组都是倒了,反转一下便可
reverse(nums.begin(), nums.end());
}
};

View File

@ -389,6 +389,51 @@ class Solution:
### Go
```go
func searchRange(nums []int, target int) []int {
leftBorder := getLeft(nums, target)
rightBorder := getRight(nums, target)
// 情况一
if leftBorder == -2 || rightBorder == -2 {
return []int{-1, -1}
}
// 情况三
if rightBorder - leftBorder > 1 {
return []int{leftBorder + 1, rightBorder - 1}
}
// 情况二
return []int{-1, -1}
}
func getLeft(nums []int, target int) int {
left, right := 0, len(nums)-1
border := -2 // 记录border没有被赋值的情况这里不能赋值-1target = num[0]时,会无法区分情况一和情况二
for left <= right { // []闭区间
mid := left + ((right - left) >> 1)
if nums[mid] >= target { // 找到第一个等于target的位置
right = mid - 1
border = right
} else {
left = mid + 1
}
}
return border
}
func getRight(nums []int, target int) int {
left, right := 0, len(nums) - 1
border := -2
for left <= right {
mid := left + ((right - left) >> 1)
if nums[mid] > target {
right = mid - 1
} else { // 找到第一个大于target的位置
left = mid + 1
border = left
}
}
return border
}
```
### JavaScript

View File

@ -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>

View File

@ -346,69 +346,56 @@ class Solution {
### Go
```Go
import "strings"
var res [][]string
func isValid(board [][]string, row, col int) (res bool){
n := len(board)
for i:=0; i < row; i++ {
if board[i][col] == "Q" {
return false
}
}
for i := 0; i < n; i++{
if board[row][i] == "Q" {
return false
}
}
for i ,j := row, col; i >= 0 && j >=0 ; i, j = i - 1, j- 1{
if board[i][j] == "Q"{
return false
}
}
for i, j := row, col; i >=0 && j < n; i,j = i-1, j+1 {
if board[i][j] == "Q" {
return false
}
}
return true
}
func backtrack(board [][]string, row int) {
size := len(board)
if row == size{
temp := make([]string, size)
for i := 0; i<size;i++{
temp[i] = strings.Join(board[i],"")
}
res =append(res,temp)
return
}
for col := 0; col < size; col++ {
if !isValid(board, row, col){
continue
}
board[row][col] = "Q"
backtrack(board, row+1)
board[row][col] = "."
}
}
func solveNQueens(n int) [][]string {
res = [][]string{}
board := make([][]string, n)
for i := 0; i < n; i++{
board[i] = make([]string, n)
}
for i := 0; i < n; i++{
for j := 0; j<n;j++{
board[i][j] = "."
}
}
backtrack(board, 0)
var res [][]string
chessboard := make([][]string, n)
for i := 0; i < n; i++ {
chessboard[i] = make([]string, n)
}
for i := 0; i < n; i++ {
for j := 0; j < n; j++ {
chessboard[i][j] = "."
}
}
var backtrack func(int)
backtrack = func(row int) {
if row == n {
temp := make([]string, n)
for i, rowStr := range chessboard {
temp[i] = strings.Join(rowStr, "")
}
res = append(res, temp)
return
}
for i := 0; i < n; i++ {
if isValid(n, row, i, chessboard) {
chessboard[row][i] = "Q"
backtrack(row + 1)
chessboard[row][i] = "."
}
}
}
backtrack(0)
return res
}
return res
func isValid(n, row, col int, chessboard [][]string) bool {
for i := 0; i < row; i++ {
if chessboard[i][col] == "Q" {
return false
}
}
for i, j := row-1, col-1; i >= 0 && j >= 0; i, j = i-1, j-1 {
if chessboard[i][j] == "Q" {
return false
}
}
for i, j := row-1, col+1; i >= 0 && j < n; i, j = i-1, j+1 {
if chessboard[i][j] == "Q" {
return false
}
}
return true
}
```
### Javascript

View File

@ -143,5 +143,65 @@ var totalNQueens = function(n) {
return count;
};
```
C
```c
//path[i]为在i行path[i]列上存在皇后
int *path;
int pathTop;
int answer;
//检查当前level行index列放置皇后是否合法
int isValid(int index, int level) {
int i;
//updater为若斜角存在皇后其所应在的列
//用来检查左上45度是否存在皇后
int lCornerUpdater = index - level;
//用来检查右上135度是否存在皇后
int rCornerUpdater = index + level;
for(i = 0; i < pathTop; ++i) {
//path[i] == index检查index列是否存在皇后
//检查斜角皇后只要path[i] == updater就说明当前位置不可放置皇后。
//path[i] == lCornerUpdater检查左上角45度是否有皇后
//path[i] == rCornerUpdater检查右上角135度是否有皇后
if(path[i] == index || path[i] == lCornerUpdater || path[i] == rCornerUpdater)
return 0;
//更新updater指向下一行对应的位置
++lCornerUpdater;
--rCornerUpdater;
}
return 1;
}
//回溯算法level为当前皇后行数
void backTracking(int n, int level) {
//若path中元素个数已经为n则证明有一种解法。answer+1
if(pathTop == n) {
++answer;
return;
}
int i;
for(i = 0; i < n; ++i) {
//若当前level行i列是合法的放置位置。就将i放入path中
if(isValid(i, level)) {
path[pathTop++] = i;
backTracking(n, level + 1);
//回溯
--pathTop;
}
}
}
int totalNQueens(int n){
answer = 0;
pathTop = 0;
path = (int *)malloc(sizeof(int) * n);
backTracking(n, 0);
return answer;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -131,7 +131,46 @@ public:
* [59.螺旋矩阵II](https://leetcode-cn.com/problems/spiral-matrix-ii/)
* [剑指Offer 29.顺时针打印矩阵](https://leetcode-cn.com/problems/shun-shi-zhen-da-yin-ju-zhen-lcof/)
## 其他语言版本
Python:
```python
class Solution:
def spiralOrder(self, matrix: List[List[int]]) -> List[int]:
m, n = len(matrix), len(matrix[0])
left, right, up, down = 0, n - 1, 0, m - 1 # 定位四个方向的边界,闭区间
res = []
while True:
for i in range(left, right + 1): # 上边,从左到右
res.append(matrix[up][i])
up += 1 # 上边界下移
if len(res) >= m * n: # 判断是否已经遍历完
break
for i in range(up, down + 1): # 右边,从上到下
res.append(matrix[i][right])
right -= 1 # 右边界左移
if len(res) >= m * n:
break
for i in range(right, left - 1, -1): # 下边,从右到左
res.append(matrix[down][i])
down -= 1 # 下边界上移
if len(res) >= m * n:
break
for i in range(down, up - 1, -1): # 左边,从下到上
res.append(matrix[i][left])
left += 1 # 左边界右移
if len(res) >= m * n:
break
return res
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -287,6 +287,51 @@ var generateMatrix = function(n) {
```
TypeScript:
```typescript
function generateMatrix(n: number): number[][] {
let loopNum: number = Math.floor(n / 2);
const resArr: number[][] = new Array(n).fill(1).map(i => new Array(n));
let chunkNum: number = n - 1;
let startX: number = 0;
let startY: number = 0;
let value: number = 1;
let x: number, y: number;
while (loopNum--) {
x = startX;
y = startY;
while (x < startX + chunkNum) {
resArr[y][x] = value;
x++;
value++;
}
while (y < startY + chunkNum) {
resArr[y][x] = value;
y++;
value++;
}
while (x > startX) {
resArr[y][x] = value;
x--;
value++;
}
while (y > startY) {
resArr[y][x] = value;
y--;
value++;
}
startX++;
startY++;
chunkNum -= 2;
}
if (n % 2 === 1) {
resArr[startX][startY] = value;
}
return resArr;
};
```
Go:
```go

View File

@ -347,6 +347,42 @@ var uniquePaths = function(m, n) {
};
```
### C
```c
//初始化dp数组
int **initDP(int m, int n) {
//动态开辟dp数组
int **dp = (int**)malloc(sizeof(int *) * m);
int i, j;
for(i = 0; i < m; ++i) {
dp[i] = (int *)malloc(sizeof(int) * n);
}
//从00到i,0只有一种走法所以dp[i][0]都是1同理dp[0][j]也是1
for(i = 0; i < m; ++i)
dp[i][0] = 1;
for(j = 0; j < n; ++j)
dp[0][j] = 1;
return dp;
}
int uniquePaths(int m, int n){
//dp数组dp[i][j]代表从dp[0][0]到dp[i][j]有几种走法
int **dp = initDP(m, n);
int i, j;
//到达dp[i][j]只能从dp[i-1][j]和dp[i][j-1]出发
//dp[i][j] = dp[i-1][j] + dp[i][j-1]
for(i = 1; i < m; ++i) {
for(j = 1; j < n; ++j) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
int result = dp[m-1][n-1];
free(dp);
return result;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -4,7 +4,7 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 63. 不同路径 II
# 63. 不同路径 II
[力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/)
@ -22,23 +22,22 @@
![](https://img-blog.csdnimg.cn/20210111204939971.png)
输入obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出2
* 输入obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
* 输出2
解释:
3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
* 3x3 网格的正中间有一个障碍物。
* 从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右
示例 2
![](https://img-blog.csdnimg.cn/20210111205857918.png)
输入obstacleGrid = [[0,1],[0,0]]
输出1
* 输入obstacleGrid = [[0,1],[0,0]]
* 输出1
提示:
* m == obstacleGrid.length
* n == obstacleGrid[i].length
* 1 <= m, n <= 100
@ -171,7 +170,7 @@ public:
## 其他语言版本
Java
### Java
```java
class Solution {
@ -199,7 +198,7 @@ class Solution {
```
Python
### Python
```python
class Solution:
@ -262,54 +261,41 @@ class Solution:
```
Go
### Go
```go
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
m,n:= len(obstacleGrid),len(obstacleGrid[0])
m, n := len(obstacleGrid), len(obstacleGrid[0])
// 定义一个dp数组
dp := make([][]int,m)
for i,_ := range dp {
dp[i] = make([]int,n)
dp := make([][]int, m)
for i, _ := range dp {
dp[i] = make([]int, n)
}
// 初始化
for i:=0;i<m;i++ {
// 如果是障碍物, 后面的就都是0, 不用循环了
if obstacleGrid[i][0] == 1 {
break
}
dp[i][0]=1
// 初始化, 如果是障碍物, 后面的就都是0, 不用循环了
for i := 0; i < m && obstacleGrid[i][0] == 0; i++ {
dp[i][0] = 1
}
for i:=0;i<n;i++ {
if obstacleGrid[0][i] == 1 {
break
}
dp[0][i]=1
for i := 0; i < n && obstacleGrid[0][i] == 0; i++ {
dp[0][i] = 1
}
// dp数组推导过程
for i:=1;i<m;i++ {
for j:=1;j<n;j++ {
// 如果obstacleGrid[i][j]这个点是障碍物, 那么我们的dp[i][j]保持为0
if obstacleGrid[i][j] != 1 {
for i := 1; i < m; i++ {
for j := 1; j < n; j++ {
// 如果obstacleGrid[i][j]这个点是障碍物, 那么dp[i][j]保持为0
if obstacleGrid[i][j] != 1 {
// 否则我们需要计算当前点可以到达的路径数
dp[i][j] = dp[i-1][j]+dp[i][j-1]
dp[i][j] = dp[i-1][j] + dp[i][j-1]
}
}
}
// debug遍历dp
//for i,_ := range dp {
// for j,_ := range dp[i] {
// fmt.Printf("%.2v,",dp[i][j])
// }
// fmt.Println()
//}
return dp[m-1][n-1]
}
```
Javascript
``` Javascript
### Javascript
```Javascript
var uniquePathsWithObstacles = function(obstacleGrid) {
const m = obstacleGrid.length
const n = obstacleGrid[0].length
@ -333,6 +319,60 @@ var uniquePathsWithObstacles = function(obstacleGrid) {
};
```
C
```c
//初始化dp数组
int **initDP(int m, int n, int** obstacleGrid) {
int **dp = (int**)malloc(sizeof(int*) * m);
int i, j;
//初始化每一行数组
for(i = 0; i < m; ++i) {
dp[i] = (int*)malloc(sizeof(int) * n);
}
//先将第一行第一列设为0
for(i = 0; i < m; ++i) {
dp[i][0] = 0;
}
for(j = 0; j < n; ++j) {
dp[0][j] = 0;
}
//若碰到障碍,之后的都走不了。退出循环
for(i = 0; i < m; ++i) {
if(obstacleGrid[i][0]) {
break;
}
dp[i][0] = 1;
}
for(j = 0; j < n; ++j) {
if(obstacleGrid[0][j])
break;
dp[0][j] = 1;
}
return dp;
}
int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, int* obstacleGridColSize){
int m = obstacleGridSize, n = *obstacleGridColSize;
//初始化dp数组
int **dp = initDP(m, n, obstacleGrid);
int i, j;
for(i = 1; i < m; ++i) {
for(j = 1; j < n; ++j) {
//若当前i,j位置有障碍
if(obstacleGrid[i][j])
//路线不同
dp[i][j] = 0;
else
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
//返回最后终点的路径个数
return dp[m-1][n-1];
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -296,6 +296,48 @@ var climbStairs = function(n) {
};
```
### C
```c
int climbStairs(int n){
//若n<=2返回n
if(n <= 2)
return n;
//初始化dp数组数组大小为n+1
int *dp = (int *)malloc(sizeof(int) * (n + 1));
dp[0] = 0, dp[1] = 1, dp[2] = 2;
//从前向后遍历数组dp[i] = dp[i-1] + dp[i-2]
int i;
for(i = 3; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
//返回dp[n]
return dp[n];
}
```
优化空间复杂度:
```c
int climbStairs(int n){
//若n<=2返回n
if(n <= 2)
return n;
//初始化dp数组数组大小为3
int *dp = (int *)malloc(sizeof(int) * 3);
dp[1] = 1, dp[2] = 2;
//只记录前面两个台阶的状态
int i;
for(i = 3; i <= n; ++i) {
int sum = dp[1] + dp[2];
dp[1] = dp[2];
dp[2] = sum;
}
//返回dp[2]
return dp[2];
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -4,7 +4,7 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 96.不同的二叉搜索树
# 96.不同的二叉搜索树
[力扣题目链接](https://leetcode-cn.com/problems/unique-binary-search-trees/)
@ -163,7 +163,7 @@ public:
## 其他语言版本
Java
### Java
```Java
class Solution {
public int numTrees(int n) {
@ -184,7 +184,7 @@ class Solution {
}
```
Python
### Python
```python
class Solution:
def numTrees(self, n: int) -> int:
@ -196,7 +196,7 @@ class Solution:
return dp[-1]
```
Go
### Go
```Go
func numTrees(n int)int{
dp:=make([]int,n+1)
@ -210,7 +210,7 @@ func numTrees(n int)int{
}
```
Javascript
### Javascript
```Javascript
const numTrees =(n) => {
let dp = new Array(n+1).fill(0);
@ -227,7 +227,34 @@ const numTrees =(n) => {
};
```
C:
```c
//开辟dp数组
int *initDP(int n) {
int *dp = (int *)malloc(sizeof(int) * (n + 1));
int i;
for(i = 0; i <= n; ++i)
dp[i] = 0;
return dp;
}
int numTrees(int n){
//开辟dp数组
int *dp = initDP(n);
//将dp[0]设为1
dp[0] = 1;
int i, j;
for(i = 1; i <= n; ++i) {
for(j = 1; j <= i; ++j) {
//递推公式dp[i] = dp[i] + 根为j时左子树种类个数 * 根为j时右子树种类个数
dp[i] += dp[j - 1] * dp[i - j];
}
}
return dp[n];
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -574,7 +574,87 @@ var isSymmetric = function(root) {
};
```
## Swift:
> 递归
```swift
func isSymmetric(_ root: TreeNode?) -> Bool {
return _isSymmetric(root?.left, right: root?.right)
}
func _isSymmetric(_ left: TreeNode?, right: TreeNode?) -> Bool {
// 首先排除空节点情况
if left == nil && right == nil {
return true
} else if left == nil && right != nil {
return false
} else if left != nil && right == nil {
return false
} else if left!.val != right!.val {
// 进而排除数值不相等的情况
return false
}
// left 和 right 都不为空, 且数值也相等就递归
let inSide = _isSymmetric(left!.right, right: right!.left)
let outSide = _isSymmetric(left!.left, right: right!.right)
return inSide && outSide
}
```
> 迭代 - 使用队列
```swift
func isSymmetric2(_ root: TreeNode?) -> Bool {
guard let root = root else {
return true
}
var queue = [TreeNode?]()
queue.append(root.left)
queue.append(root.right)
while !queue.isEmpty {
let left = queue.removeFirst()
let right = queue.removeFirst()
if left == nil && right == nil {
continue
}
if left == nil || right == nil || left?.val != right?.val {
return false
}
queue.append(left!.left)
queue.append(right!.right)
queue.append(left!.right)
queue.append(right!.left)
}
return true
}
```
> 迭代 - 使用栈
```swift
func isSymmetric3(_ root: TreeNode?) -> Bool {
guard let root = root else {
return true
}
var stack = [TreeNode?]()
stack.append(root.left)
stack.append(root.right)
while !stack.isEmpty {
let left = stack.removeLast()
let right = stack.removeLast()
if left == nil && right == nil {
continue
}
if left == nil || right == nil || left?.val != right?.val {
return false
}
stack.append(left!.left)
stack.append(right!.right)
stack.append(left!.right)
stack.append(right!.left)
}
return true
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -246,6 +246,34 @@ var levelOrder = function(root) {
```
Swift:
```swift
func levelOrder(_ root: TreeNode?) -> [[Int]] {
var res = [[Int]]()
guard let root = root else {
return res
}
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var sub = [Int]()
for _ in 0 ..< size {
let node = queue.removeFirst()
sub.append(node.val)
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
res.append(sub)
}
return res
}
```
**此时我们就掌握了二叉树的层序遍历了,那么如下九道力扣上的题目,只需要修改模板的两三行代码(不能再多了),便可打倒!**
@ -426,6 +454,31 @@ var levelOrderBottom = function(root) {
};
```
Swift:
```swift
func levelOrderBottom(_ root: TreeNode?) -> [[Int]] {
var res = [[Int]]()
guard let root = root else {
return res
}
var queue: [TreeNode] = [root]
while !queue.isEmpty {
var sub = [Int]()
for _ in 0 ..< queue.count {
let node = queue.removeFirst()
sub.append(node.val)
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
res.insert(sub, at: 0)
}
return res
}
```
# 199.二叉树的右视图
@ -604,6 +657,36 @@ var rightSideView = function(root) {
};
```
Swift:
```swift
func rightSideView(_ root: TreeNode?) -> [Int] {
var res = [Int]()
guard let root = root else {
return res
}
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
for i in 0 ..< size {
let node = queue.removeFirst()
if i == size - 1 {
// 保存 每层最后一个元素
res.append(node.val)
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return res
}
```
# 637.二叉树的层平均值
[力扣题目链接](https://leetcode-cn.com/problems/average-of-levels-in-binary-tree/)
@ -785,6 +868,34 @@ var averageOfLevels = function(root) {
};
```
Swift:
```swift
func averageOfLevels(_ root: TreeNode?) -> [Double] {
var res = [Double]()
guard let root = root else {
return res
}
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var sum = 0
for _ in 0 ..< size {
let node = queue.removeFirst()
sum += node.val
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
res.append(Double(sum) / Double(size))
}
return res
}
```
# 429.N叉树的层序遍历
[力扣题目链接](https://leetcode-cn.com/problems/n-ary-tree-level-order-traversal/)
@ -981,6 +1092,31 @@ var levelOrder = function(root) {
};
```
Swift:
```swift
func levelOrder(_ root: Node?) -> [[Int]] {
var res = [[Int]]()
guard let root = root else {
return res
}
var queue = [Node]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var sub = [Int]()
for _ in 0 ..< size {
let node = queue.removeFirst()
sub.append(node.val)
for childNode in node.children {
queue.append(childNode)
}
}
res.append(sub)
}
return res
}
```
# 515.在每个树行中找最大值
[力扣题目链接](https://leetcode-cn.com/problems/find-largest-value-in-each-tree-row/)
@ -1136,6 +1272,36 @@ var largestValues = function(root) {
};
```
Swift:
```swift
func largestValues(_ root: TreeNode?) -> [Int] {
var res = [Int]()
guard let root = root else {
return res
}
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var max: Int = Int.min
for _ in 0 ..< size {
let node = queue.removeFirst()
if node.val > max {
max = node.val
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
res.append(max)
}
return res
}
```
# 116.填充每个节点的下一个右侧节点指针
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node/)
@ -1338,6 +1504,37 @@ func connect(root *Node) *Node {
}
```
Swift:
```swift
func connect(_ root: Node?) -> Node? {
guard let root = root else {
return nil
}
var queue = [Node]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var preNode: Node?
for i in 0 ..< size {
let node = queue.removeFirst()
if i == 0 {
preNode = node
} else {
preNode?.next = node
preNode = node
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return root
}
```
# 117.填充每个节点的下一个右侧节点指针II
[力扣题目链接](https://leetcode-cn.com/problems/populating-next-right-pointers-in-each-node-ii/)
@ -1532,6 +1729,38 @@ func connect(root *Node) *Node {
return root
}
```
Swift
```swift
func connect(_ root: Node?) -> Node? {
guard let root = root else {
return nil
}
var queue = [Node]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
var preNode: Node?
for i in 0 ..< size {
let node = queue.removeFirst()
if i == 0 {
preNode = node
} else {
preNode?.next = node
preNode = node
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return root
}
```
# 104.二叉树的最大深度
[力扣题目链接](https://leetcode-cn.com/problems/maximum-depth-of-binary-tree/)
@ -1704,6 +1933,31 @@ var maxDepth = function(root) {
};
```
Swift:
```swift
func maxDepth(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var queue = [TreeNode]()
queue.append(root)
var res: Int = 0
while !queue.isEmpty {
for _ in 0 ..< queue.count {
let node = queue.removeFirst()
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
res += 1
}
return res
}
```
# 111.二叉树的最小深度
[力扣题目链接](https://leetcode-cn.com/problems/minimum-depth-of-binary-tree/)
@ -1876,7 +2130,33 @@ var minDepth = function(root) {
};
```
Swift
```swift
func minDepth(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var res = 0
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
res += 1
for _ in 0 ..< queue.count {
let node = queue.removeFirst()
if node.left == nil && node.right == nil {
return res
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return res
}
```
# 总结

View File

@ -653,5 +653,82 @@ int maxDepth(struct TreeNode* root){
}
```
## Swift
>二叉树最大深度
```swift
// 递归 - 后序
func maxDepth1(_ root: TreeNode?) -> Int {
return _maxDepth1(root)
}
func _maxDepth1(_ root: TreeNode?) -> Int {
if root == nil {
return 0
}
let leftDepth = _maxDepth1(root!.left)
let rightDepth = _maxDepth1(root!.right)
return 1 + max(leftDepth, rightDepth)
}
// 层序
func maxDepth(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var queue = [TreeNode]()
queue.append(root)
var res: Int = 0
while !queue.isEmpty {
res += 1
for _ in 0 ..< queue.count {
let node = queue.removeFirst()
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return res
}
```
>N叉树最大深度
```swift
// 递归
func maxDepth(_ root: Node?) -> Int {
guard let root = root else {
return 0
}
var depth = 0
for node in root.children {
depth = max(depth, maxDepth(node))
}
return depth + 1
}
// 迭代-层序遍历
func maxDepth1(_ root: Node?) -> Int {
guard let root = root else {
return 0
}
var depth = 0
var queue = [Node]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
depth += 1
for _ in 0 ..< size {
let node = queue.removeFirst()
for child in node.children {
queue.append(child)
}
}
}
return depth
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -816,6 +816,7 @@ var buildTree = function(preorder, inorder) {
## C
106 从中序与后序遍历序列构造二叉树
```c
int linearSearch(int* arr, int arrSize, int key) {
int i;
@ -847,6 +848,7 @@ struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int po
```
105 从前序与中序遍历序列构造二叉树
```c
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
// 递归结束条件传入的数组大小为0
@ -889,5 +891,100 @@ struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int in
}
```
## Swift
105 从前序与中序遍历序列构造二叉树
```swift
class Solution {
func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? {
return helper(preorder: preorder,
preorderBegin: 0,
preorderEnd: preorder.count,
inorder: inorder,
inorderBegin: 0,
inorderEnd: inorder.count)
}
func helper(preorder: [Int], preorderBegin: Int, preorderEnd: Int, inorder: [Int], inorderBegin: Int, inorderEnd: Int) -> TreeNode? {
if preorderBegin == preorderEnd {
return nil
}
// 前序遍历数组的第一个元素作为分割点
let rootValue = preorder[preorderBegin]
let root = TreeNode(rootValue)
if preorderEnd - preorderBegin == 1 {
return root
}
var index = 0 // 从中序遍历数组中找到根节点的下标
if let ind = inorder.firstIndex(of: rootValue) {
index = ind
}
// 递归
root.left = helper(preorder: preorder,
preorderBegin: preorderBegin + 1,
preorderEnd: preorderBegin + 1 + index - inorderBegin,
inorder: inorder,
inorderBegin: inorderBegin,
inorderEnd: index)
root.right = helper(preorder: preorder,
preorderBegin: preorderBegin + 1 + index - inorderBegin,
preorderEnd: preorderEnd,
inorder: inorder,
inorderBegin: index + 1,
inorderEnd: inorderEnd)
return root
}
}
```
106 从中序与后序遍历序列构造二叉树
```swift
class Solution_0106 {
func buildTree(inorder: [Int], inorderBegin: Int, inorderEnd: Int, postorder: [Int], postorderBegin: Int, postorderEnd: Int) -> TreeNode? {
if postorderEnd - postorderBegin < 1 {
return nil
}
// 后序遍历数组的最后一个元素作为分割点
let rootValue = postorder[postorderEnd - 1]
let root = TreeNode(rootValue)
if postorderEnd - postorderBegin == 1 {
return root
}
// 从中序遍历数组中找到根节点的下标
var delimiterIndex = 0
if let index = inorder.firstIndex(of: rootValue) {
delimiterIndex = index
}
root.left = buildTree(inorder: inorder,
inorderBegin: inorderBegin,
inorderEnd: delimiterIndex,
postorder: postorder,
postorderBegin: postorderBegin,
postorderEnd: postorderBegin + (delimiterIndex - inorderBegin))
root.right = buildTree(inorder: inorder,
inorderBegin: delimiterIndex + 1,
inorderEnd: inorderEnd,
postorder: postorder,
postorderBegin: postorderBegin + (delimiterIndex - inorderBegin),
postorderEnd: postorderEnd - 1)
return root
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -730,5 +730,33 @@ bool isBalanced(struct TreeNode* root){
}
```
## Swift:
>递归
```swift
func isBalanced(_ root: TreeNode?) -> Bool {
// -1 已经不是平衡二叉树
return getHeight(root) == -1 ? false : true
}
func getHeight(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
let leftHeight = getHeight(root.left)
if leftHeight == -1 {
return -1
}
let rightHeight = getHeight(root.right)
if rightHeight == -1 {
return -1
}
if abs(leftHeight - rightHeight) > 1 {
return -1
} else {
return 1 + max(leftHeight, rightHeight)
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -404,8 +404,51 @@ var minDepth = function(root) {
};
```
## Swift
> 递归
```Swift
func minDepth(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
if root.left == nil && root.right != nil {
return 1 + minDepth(root.right)
}
if root.left != nil && root.right == nil {
return 1 + minDepth(root.left)
}
return 1 + min(minDepth(root.left), minDepth(root.right))
}
```
> 迭代
```Swift
func minDepth(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var res = 0
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
res += 1
for _ in 0 ..< queue.count {
let node = queue.removeFirst()
if node.left == nil && node.right == nil {
return res
}
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return res
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -766,7 +766,124 @@ let pathSum = function(root, targetSum) {
};
```
## Swift
0112.路径总和
**递归**
```swift
func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
guard let root = root else {
return false
}
return traversal(root, targetSum - root.val)
}
func traversal(_ cur: TreeNode?, _ count: Int) -> Bool {
if cur?.left == nil && cur?.right == nil && count == 0 {
return true
}
if cur?.left == nil && cur?.right == nil {
return false
}
if let leftNode = cur?.left {
if traversal(leftNode, count - leftNode.val) {
return true
}
}
if let rightNode = cur?.right {
if traversal(rightNode, count - rightNode.val) {
return true
}
}
return false
}
```
**迭代**
```swift
func hasPathSum(_ root: TreeNode?, _ targetSum: Int) -> Bool {
guard let root = root else {
return false
}
var stack = Array<(TreeNode, Int)>()
stack.append((root, root.val))
while !stack.isEmpty {
let node = stack.removeLast()
if node.0.left == nil && node.0.right == nil && targetSum == node.1 {
return true
}
if let rightNode = node.0.right {
stack.append((rightNode, node.1 + rightNode.val))
}
if let leftNode = node.0.left {
stack.append((leftNode, node.1 + leftNode.val))
}
}
return false
}
```
0113.路径总和 II
**递归**
```swift
var result = [[Int]]()
var path = [Int]()
func pathSum(_ root: TreeNode?, _ targetSum: Int) -> [[Int]] {
result.removeAll()
path.removeAll()
guard let root = root else {
return result
}
path.append(root.val)
traversal(root, count: targetSum - root.val)
return result
}
func traversal(_ cur: TreeNode?, count: Int) {
var count = count
// 遇到了叶子节点且找到了和为targetSum的路径
if cur?.left == nil && cur?.right == nil && count == 0 {
result.append(path)
return
}
// 遇到叶子节点而没有找到合适的边,直接返回
if cur?.left == nil && cur?.right == nil{
return
}
if let leftNode = cur?.left {
path.append(leftNode.val)
count -= leftNode.val
traversal(leftNode, count: count)// 递归
count += leftNode.val// 回溯
path.removeLast()// 回溯
}
if let rightNode = cur?.right {
path.append(rightNode.val)
count -= rightNode.val
traversal(rightNode, count: count)// 递归
count += rightNode.val// 回溯
path.removeLast()// 回溯
}
return
}
```

View File

@ -289,7 +289,33 @@ var sumNumbers = function(root) {
};
```
C:
```c
//sum记录总和
int sum;
void traverse(struct TreeNode *node, int val) {
//更新val为根节点到当前节点的和
val = val * 10 + node->val;
//若当前节点为叶子节点记录val
if(!node->left && !node->right) {
sum+=val;
return;
}
//若有左/右节点,遍历左/右节点
if(node->left)
traverse(node->left, val);
if(node->right)
traverse(node->right, val);
}
int sumNumbers(struct TreeNode* root){
sum = 0;
traverse(root, 0);
return sum;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -587,5 +587,57 @@ func partition(_ s: String) -> [[String]] {
}
```
## Rust
```rust
impl Solution {
pub fn partition(s: String) -> Vec<Vec<String>> {
let mut ret = vec![];
let mut path = vec![];
let sub_str: Vec<char> = s.chars().collect();
Self::backtracing(&sub_str, 0, &mut ret, &mut path);
ret
}
fn backtracing(sub_str: &Vec<char>, start: usize, ret: &mut Vec<Vec<String>>, path: &mut Vec<String>) {
//如果起始位置大于s的大小说明找到了一组分割方案
if start >= sub_str.len() {
ret.push(path.clone());
return;
}
for i in start..sub_str.len() {
if !Self::is_palindrome(sub_str, start, i) {
continue;
}
//如果是回文子串,则记录
let s: String = sub_str[start..i+1].into_iter().collect();
path.push(s);
//起始位置后移,保证不重复
Self::backtracing(sub_str, i+1, ret, path);
path.pop();
}
}
fn is_palindrome(s: &Vec<char>, start: usize, end: usize) -> bool {
let (mut start, mut end) = (start, end);
while start < end {
if s[start] != s[end] {
return false;
}
start += 1;
end -= 1;
}
true
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -294,7 +294,30 @@ var detectCycle = function(head) {
};
```
TypeScript
```typescript
function detectCycle(head: ListNode | null): ListNode | null {
let slowNode: ListNode | null = head,
fastNode: ListNode | null = head;
while (fastNode !== null && fastNode.next !== null) {
slowNode = (slowNode as ListNode).next;
fastNode = fastNode.next.next;
if (slowNode === fastNode) {
slowNode = head;
while (slowNode !== fastNode) {
slowNode = (slowNode as ListNode).next;
fastNode = (fastNode as ListNode).next;
}
return slowNode;
}
}
return null;
};
```
Swift:
```swift
class Solution {
func detectCycle(_ head: ListNode?) -> ListNode? {

View File

@ -439,7 +439,75 @@ var reorderList = function(head, s = [], tmp) {
}
```
### C
方法三:反转链表
```c
//翻转链表
struct ListNode *reverseList(struct ListNode *head) {
if(!head)
return NULL;
struct ListNode *preNode = NULL, *curNode = head;
while(curNode) {
//创建tempNode记录curNode->next即将被更新
struct ListNode* tempNode = curNode->next;
//将curNode->next指向preNode
curNode->next = preNode;
//更新preNode为curNode
preNode = curNode;
//curNode更新为原链表中下一个元素
curNode = tempNode;
}
return preNode;
}
void reorderList(struct ListNode* head){
//slow用来截取到链表的中间节点(第一个链表的最后节点)每次循环跳一个节点。fast用来辅助每次循环跳两个节点
struct ListNode *fast = head, *slow = head;
while(fast && fast->next && fast->next->next) {
//fast每次跳两个节点
fast = fast->next->next;
//slow每次跳一个节点
slow = slow->next;
}
//将slow->next后的节点翻转
struct ListNode *sndLst = reverseList(slow->next);
//将第一个链表与第二个链表断开
slow->next = NULL;
//因为插入从curNode->next开始curNode刚开始已经head。所以fstList要从head->next开始
struct ListNode *fstLst = head->next;
struct ListNode *curNode = head;
int count = 0;
//当第一个链表和第二个链表中都有节点时循环
while(sndLst && fstLst) {
//count为奇数插入fstLst中的节点
if(count % 2) {
curNode->next = fstLst;
fstLst = fstLst->next;
}
//count为偶数插入sndList的节点
else {
curNode->next = sndLst;
sndLst = sndLst->next;
}
//设置下一个节点
curNode = curNode->next;
//更新count
++count;
}
//若两个链表fstList和sndLst中还有节点将其放入链表
if(fstLst) {
curNode->next = fstLst;
}
if(sndLst) {
curNode->next = sndLst;
}
//返回链表
return head;
}
```
-----------------------

View File

@ -133,39 +133,26 @@ public:
java:
```Java
public class EvalRPN {
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> stack = new LinkedList();
for (String token : tokens) {
char c = token.charAt(0);
if (!isOpe(token)) {
stack.addFirst(stoi(token));
} else if (c == '+') {
stack.push(stack.pop() + stack.pop());
} else if (c == '-') {
stack.push(- stack.pop() + stack.pop());
} else if (c == '*') {
stack.push( stack.pop() * stack.pop());
for (int i = 0; i < tokens.length; ++i) {
if ("+".equals(tokens[i])) { // leetcode 内置jdk的问题不能使用==判断字符串是否相等
stack.push(stack.pop() + stack.pop()); // 注意 - 和/ 需要特殊处理
} else if ("-".equals(tokens[i])) {
stack.push(-stack.pop() + stack.pop());
} else if ("*".equals(tokens[i])) {
stack.push(stack.pop() * stack.pop());
} else if ("/".equals(tokens[i])) {
int temp1 = stack.pop();
int temp2 = stack.pop();
stack.push(temp2 / temp1);
} else {
int num1 = stack.pop();
int num2 = stack.pop();
stack.push( num2/num1);
stack.push(Integer.valueOf(tokens[i]));
}
}
return stack.pop();
}
private boolean isOpe(String s) {
return s.length() == 1 && s.charAt(0) <'0' || s.charAt(0) >'9';
}
private int stoi(String s) {
return Integer.valueOf(s);
}
public static void main(String[] args) {
new EvalRPN().evalRPN(new String[] {"10","6","9","3","+","-11","*","/","*","17","+","5","+"});
}
}
```
@ -223,6 +210,71 @@ var evalRPN = function(tokens) {
};
```
TypeScript
普通版:
```typescript
function evalRPN(tokens: string[]): number {
let helperStack: number[] = [];
let temp: number;
let i: number = 0;
while (i < tokens.length) {
let t: string = tokens[i];
switch (t) {
case '+':
temp = helperStack.pop()! + helperStack.pop()!;
helperStack.push(temp);
break;
case '-':
temp = helperStack.pop()!;
temp = helperStack.pop()! - temp;
helperStack.push(temp);
break;
case '*':
temp = helperStack.pop()! * helperStack.pop()!;
helperStack.push(temp);
break;
case '/':
temp = helperStack.pop()!;
temp = Math.trunc(helperStack.pop()! / temp);
helperStack.push(temp);
break;
default:
helperStack.push(Number(t));
break;
}
i++;
}
return helperStack.pop()!;
};
```
优化版:
```typescript
function evalRPN(tokens: string[]): number {
const helperStack: number[] = [];
const operatorMap: Map<string, (a: number, b: number) => number> = new Map([
['+', (a, b) => a + b],
['-', (a, b) => a - b],
['/', (a, b) => Math.trunc(a / b)],
['*', (a, b) => a * b],
]);
let a: number, b: number;
for (let t of tokens) {
if (operatorMap.has(t)) {
b = helperStack.pop()!;
a = helperStack.pop()!;
helperStack.push(operatorMap.get(t)!(a, b));
} else {
helperStack.push(Number(t));
}
}
return helperStack.pop()!;
};
```
python3
```python

View File

@ -40,7 +40,7 @@
不能使用辅助空间之后,那么只能在原字符串上下功夫了。
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒了,那么再把单词反转一下,单词不就正过来了。
想一下,我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒了,那么再把单词反转一下,单词不就正过来了。
所以解题思路如下:
@ -553,6 +553,65 @@ function reverse(strArr, start, end) {
}
```
TypeScript
```typescript
function reverseWords(s: string): string {
/** Utils **/
// 删除多余空格, 如' hello world ' => 'hello world'
function delExtraSpace(arr: string[]): void {
let left: number = 0,
right: number = 0,
length: number = arr.length;
while (right < length && arr[right] === ' ') {
right++;
}
while (right < length) {
if (arr[right] === ' ' && arr[right - 1] === ' ') {
right++;
continue;
}
arr[left++] = arr[right++];
}
if (arr[left - 1] === ' ') {
arr.length = left - 1;
} else {
arr.length = left;
}
}
// 翻转字符串,如:'hello' => 'olleh'
function reverseWords(strArr: string[], start: number, end: number) {
let temp: string;
while (start < end) {
temp = strArr[start];
strArr[start] = strArr[end];
strArr[end] = temp;
start++;
end--;
}
}
/** Main code **/
let strArr: string[] = s.split('');
delExtraSpace(strArr);
let length: number = strArr.length;
// 翻转整个字符串
reverseWords(strArr, 0, length - 1);
let start: number = 0,
end: number = 0;
while (start < length) {
end = start;
while (strArr[end] !== ' ' && end < length) {
end++;
}
// 翻转单个单词
reverseWords(strArr, start, end - 1);
start = end + 1;
}
return strArr.join('');
};
```
Swift:
```swift

View File

@ -232,7 +232,27 @@ var isHappy = function(n) {
};
```
TypeScript:
```typescript
function isHappy(n: number): boolean {
// Utils
// 计算val各位的平方和
function calcSum(val: number): number {
return String(val).split("").reduce((pre, cur) => (pre + Number(cur) * Number(cur)), 0);
}
let storeSet: Set<number> = new Set();
while (n !== 1 && !storeSet.has(n)) {
storeSet.add(n);
n = calcSum(n);
}
return n === 1;
};
```
Swift
```swift
// number 每个位置上的数字的平方和
func getSum(_ number: Int) -> Int {

View File

@ -302,7 +302,63 @@ var removeElements = function(head, val) {
};
```
TypeScript:
版本一(在原链表上直接删除):
```typescript
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function removeElements(head: ListNode | null, val: number): ListNode | null {
// 删除头部节点
while (head !== null && head.val === val) {
head = head.next;
}
if (head === null) return head;
let pre: ListNode = head, cur: ListNode = head.next;
// 删除非头部节点
while (cur) {
if (cur.val === val) {
pre.next = cur.next;
} else {
pre = pre.next;
}
cur = cur.next;
}
return head;
};
```
版本二(虚拟头节点):
```typescript
function removeElements(head: ListNode | null, val: number): ListNode | null {
head = new ListNode(0, head);
let pre: ListNode = head, cur: ListNode = head.next;
// 删除非头部节点
while (cur) {
if (cur.val === val) {
pre.next = cur.next;
} else {
pre = pre.next;
}
cur = cur.next;
}
return head.next;
};
```
Swift
```swift
/**
* Definition for singly-linked list.

View File

@ -314,6 +314,54 @@ var reverseList = function(head) {
};
```
TypeScript:
```typescript
// 双指针法
function reverseList(head: ListNode | null): ListNode | null {
let preNode: ListNode | null = null,
curNode: ListNode | null = head,
tempNode: ListNode | null;
while (curNode) {
tempNode = curNode.next;
curNode.next = preNode;
preNode = curNode;
curNode = tempNode;
}
return preNode;
};
// 递归(从前往后翻转)
function reverseList(head: ListNode | null): ListNode | null {
function recur(preNode: ListNode | null, curNode: ListNode | null): ListNode | null {
if (curNode === null) return preNode;
let tempNode: ListNode | null = curNode.next;
curNode.next = preNode;
preNode = curNode;
curNode = tempNode;
return recur(preNode, curNode);
}
return recur(null, head);
};
// 递归(从后往前翻转)
function reverseList(head: ListNode | null): ListNode | null {
if (head === null) return null;
let newHead: ListNode | null;
function recur(node: ListNode | null, preNode: ListNode | null): void {
if (node.next === null) {
newHead = node;
newHead.next = preNode;
} else {
recur(node.next, node);
node.next = preNode;
}
}
recur(head, null);
return newHead;
};
```
Ruby:
```ruby

View File

@ -213,6 +213,28 @@ var minSubArrayLen = function(target, nums) {
};
```
Typescript
```typescript
function minSubArrayLen(target: number, nums: number[]): number {
let left: number = 0, right: number = 0;
let res: number = nums.length + 1;
let sum: number = 0;
while (right < nums.length) {
sum += nums[right];
if (sum >= target) {
// 不断移动左指针,直到不能再缩小为止
while (sum - nums[left] >= target) {
sum -= nums[left++];
}
res = Math.min(res, right - left + 1);
}
right++;
}
return res === nums.length + 1 ? 0 : res;
};
```
Swift:
```swift
@ -308,5 +330,55 @@ def min_sub_array_len(target, nums)
end
```
C:
暴力解法:
```c
int minSubArrayLen(int target, int* nums, int numsSize){
//初始化最小长度为INT_MAX
int minLength = INT_MAX;
int sum;
int left, right;
for(left = 0; left < numsSize; ++left) {
//每次遍历都清零sum计算当前位置后和>=target的子数组的长度
sum = 0;
//从left开始sum中添加元素
for(right = left; right < numsSize; ++right) {
sum += nums[right];
//若加入当前元素后和大于target则更新minLength
if(sum >= target) {
int subLength = right - left + 1;
minLength = minLength < subLength ? minLength : subLength;
}
}
}
//若minLength不为INT_MAX则返回minLnegth
return minLength == INT_MAX ? 0 : minLength;
}
```
滑动窗口:
```c
int minSubArrayLen(int target, int* nums, int numsSize){
//初始化最小长度为INT_MAX
int minLength = INT_MAX;
int sum = 0;
int left = 0, right = 0;
//右边界向右扩展
for(; right < numsSize; ++right) {
sum += nums[right];
//当sum的值大于等于target时保存长度并且收缩左边界
while(sum >= target) {
int subLength = right - left + 1;
minLength = minLength < subLength ? minLength : subLength;
sum -= nums[left++];
}
}
//若minLength不为INT_MAX则返回minLnegth
return minLength == INT_MAX ? 0 : minLength;
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -522,5 +522,73 @@ int countNodes(struct TreeNode* root){
}
```
## Swift:
> 递归
```swift
func countNodes(_ root: TreeNode?) -> Int {
return _countNodes(root)
}
func _countNodes(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
let leftCount = _countNodes(root.left)
let rightCount = _countNodes(root.right)
return 1 + leftCount + rightCount
}
```
> 层序遍历
```Swift
func countNodes(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var res = 0
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let size = queue.count
for _ in 0 ..< size {
let node = queue.removeFirst()
res += 1
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
}
return res
}
```
> 利用完全二叉树性质
```Swift
func countNodes(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var leftNode = root.left
var rightNode = root.right
var leftDepth = 0
var rightDepth = 0
while leftNode != nil {
leftNode = leftNode!.left
leftDepth += 1
}
while rightNode != nil {
rightNode = rightNode!.right
rightDepth += 1
}
if leftDepth == rightDepth {
return (2 << leftDepth) - 1
}
return countNodes(root.left) + countNodes(root.right) + 1
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -46,7 +46,7 @@
模拟的队列执行语句如下:
```
```cpp
queue.push(1);
queue.push(2);
queue.pop(); // 注意弹出的操作
@ -598,7 +598,80 @@ MyStack.prototype.empty = function() {
```
TypeScript:
版本一:使用两个队列模拟栈
```typescript
class MyStack {
private queue: number[];
private tempQueue: number[];
constructor() {
this.queue = [];
this.tempQueue = [];
}
push(x: number): void {
this.queue.push(x);
}
pop(): number {
for (let i = 0, length = this.queue.length - 1; i < length; i++) {
this.tempQueue.push(this.queue.shift()!);
}
let res: number = this.queue.pop()!;
let temp: number[] = this.queue;
this.queue = this.tempQueue;
this.tempQueue = temp;
return res;
}
top(): number {
let res: number = this.pop();
this.push(res);
return res;
}
empty(): boolean {
return this.queue.length === 0;
}
}
```
版本二:使用一个队列模拟栈
```typescript
class MyStack {
private queue: number[];
constructor() {
this.queue = [];
}
push(x: number): void {
this.queue.push(x);
}
pop(): number {
for (let i = 0, length = this.queue.length - 1; i < length; i++) {
this.queue.push(this.queue.shift()!);
}
return this.queue.shift()!;
}
top(): number {
let res: number = this.pop();
this.push(res);
return res;
}
empty(): boolean {
return this.queue.length === 0;
}
}
```
Swift
```Swift
// 定义一个队列数据结构
class Queue {

View File

@ -609,5 +609,43 @@ struct TreeNode* invertTree(struct TreeNode* root){
}
```
### Swift
```swift
// 前序遍历-递归
func invertTree(_ root: TreeNode?) -> TreeNode? {
guard let root = root else {
return root
}
let tmp = root.left
root.left = root.right
root.right = tmp
let _ = invertTree(root.left)
let _ = invertTree(root.right)
return root
}
// 层序遍历-迭代
func invertTree1(_ root: TreeNode?) -> TreeNode? {
guard let root = root else {
return nil
}
var queue = [TreeNode]()
queue.append(root)
while !queue.isEmpty {
let node = queue.removeFirst()
let tmp = node.left
node.left = node.right
node.right = tmp
if let left = node.left {
queue.append(left)
}
if let right = node.right {
queue.append(right)
}
}
return root
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -21,7 +21,7 @@ empty() -- 返回队列是否为空。
示例:
```
```cpp
MyQueue queue = new MyQueue();
queue.push(1);
queue.push(2);
@ -348,7 +348,44 @@ MyQueue.prototype.empty = function() {
};
```
TypeScript:
```typescript
class MyQueue {
private stackIn: number[]
private stackOut: number[]
constructor() {
this.stackIn = [];
this.stackOut = [];
}
push(x: number): void {
this.stackIn.push(x);
}
pop(): number {
if (this.stackOut.length === 0) {
while (this.stackIn.length > 0) {
this.stackOut.push(this.stackIn.pop()!);
}
}
return this.stackOut.pop()!;
}
peek(): number {
let temp: number = this.pop();
this.stackOut.push(temp);
return temp;
}
empty(): boolean {
return this.stackIn.length === 0 && this.stackOut.length === 0;
}
}
```
Swift
```swift
class MyQueue {

View File

@ -395,30 +395,102 @@ func maxSlidingWindow(nums []int, k int) []int {
Javascript:
```javascript
/**
* @param {number[]} nums
* @param {number} k
* @return {number[]}
*/
var maxSlidingWindow = function (nums, k) {
// 队列数组(存放的是元素下标,为了取值方便)
const q = [];
// 结果数组
const ans = [];
for (let i = 0; i < nums.length; i++) {
// 若队列不为空,且当前元素大于等于队尾所存下标的元素,则弹出队尾
while (q.length && nums[i] >= nums[q[q.length - 1]]) {
q.pop();
class MonoQueue {
queue;
constructor() {
this.queue = [];
}
enqueue(value) {
let back = this.queue[this.queue.length - 1];
while (back !== undefined && back < value) {
this.queue.pop();
back = this.queue[this.queue.length - 1];
}
this.queue.push(value);
}
dequeue(value) {
let front = this.front();
if (front === value) {
this.queue.shift();
}
}
front() {
return this.queue[0];
}
}
// 入队当前元素下标
q.push(i);
// 判断当前最大值(即队首元素)是否在窗口中,若不在便将其出队
if (q[0] <= i - k) {
q.shift();
let helperQueue = new MonoQueue();
let i = 0, j = 0;
let resArr = [];
while (j < k) {
helperQueue.enqueue(nums[j++]);
}
// 当达到窗口大小时便开始向结果中添加数据
if (i >= k - 1) ans.push(nums[q[0]]);
}
return ans;
resArr.push(helperQueue.front());
while (j < nums.length) {
helperQueue.enqueue(nums[j]);
helperQueue.dequeue(nums[i]);
resArr.push(helperQueue.front());
i++, j++;
}
return resArr;
};
```
TypeScript
```typescript
function maxSlidingWindow(nums: number[], k: number): number[] {
/** 单调递减队列 */
class MonoQueue {
private queue: number[];
constructor() {
this.queue = [];
};
/** 入队value如果大于队尾元素则将队尾元素删除直至队尾元素大于value或者队列为空 */
public enqueue(value: number): void {
let back: number | undefined = this.queue[this.queue.length - 1];
while (back !== undefined && back < value) {
this.queue.pop();
back = this.queue[this.queue.length - 1];
}
this.queue.push(value);
};
/** 出队只有当队头元素等于value才出队 */
public dequeue(value: number): void {
let top: number | undefined = this.top();
if (top !== undefined && top === value) {
this.queue.shift();
}
}
public top(): number | undefined {
return this.queue[0];
}
}
const helperQueue: MonoQueue = new MonoQueue();
let i: number = 0,
j: number = 0;
let resArr: number[] = [];
while (j < k) {
helperQueue.enqueue(nums[j++]);
}
resArr.push(helperQueue.top()!);
while (j < nums.length) {
helperQueue.enqueue(nums[j]);
helperQueue.dequeue(nums[i]);
resArr.push(helperQueue.top()!);
j++, i++;
}
return resArr;
};
```
Swift:
```Swift
/// 双向链表
class DoublyListNode {

View File

@ -214,7 +214,23 @@ var isAnagram = function(s, t) {
};
```
TypeScript
```typescript
function isAnagram(s: string, t: string): boolean {
if (s.length !== t.length) return false;
let helperArr: number[] = new Array(26).fill(0);
let pivot: number = 'a'.charCodeAt(0);
for (let i = 0, length = s.length; i < length; i++) {
helperArr[s.charCodeAt(i) - pivot]++;
helperArr[t.charCodeAt(i) - pivot]--;
}
return helperArr.every(i => i === 0);
};
```
Swift
```Swift
func isAnagram(_ s: String, _ t: String) -> Bool {
if s.count != t.count {

View File

@ -581,7 +581,71 @@ var binaryTreePaths = function(root) {
};
```
Swift:
> 递归/回溯
```swift
func binaryTreePaths(_ root: TreeNode?) -> [String] {
var res = [String]()
guard let root = root else {
return res
}
var path = [Int]()
_binaryTreePaths(root, path: &path, res: &res)
return res
}
func _binaryTreePaths(_ root: TreeNode, path: inout [Int], res: inout [String]) {
path.append(root.val)
if root.left == nil && root.right == nil {
var str = ""
for i in 0 ..< path.count - 1 {
str.append("\(path[i])->")
}
str.append("\(path.last!)")
res.append(str)
return
}
if let left = root.left {
_binaryTreePaths(left, path: &path, res: &res)
path.removeLast()
}
if let right = root.right {
_binaryTreePaths(right, path: &path, res: &res)
path.removeLast()
}
}
```
> 迭代
```swift
func binaryTreePaths(_ root: TreeNode?) -> [String] {
var res = [String]()
guard let root = root else {
return res
}
var stackNode = [TreeNode]()
stackNode.append(root)
var stackStr = [String]()
stackStr.append("\(root.val)")
while !stackNode.isEmpty {
let node = stackNode.popLast()!
let str = stackStr.popLast()!
if node.left == nil && node.right == nil {
res.append(str)
}
if let left = node.left {
stackNode.append(left)
stackStr.append("\(str)->\(left.val)")
}
if let right = node.right {
stackNode.append(right)
stackStr.append("\(str)->\(right.val)")
}
}
return res
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -89,9 +89,33 @@ Python
for i in range(slow, len(nums)):
nums[i] = 0
```
交换前后变量,避免补零
```python
def moveZeroes(self, nums: List[int]) -> None:
slow, fast = 0, 0
while fast < len(nums):
if nums[fast] != 0:
nums[slow], nums[fast] = nums[fast], nums[slow]
slow += 1 # 保持[0, slow)区间是没有0的
fast += 1
```
Go
```go
func moveZeroes(nums []int) {
slow := 0
for fast := 0; fast < len(nums); fast ++ {
if nums[fast] != 0 {
temp := nums[slow]
nums[slow] = nums[fast]
nums[fast] = temp
slow++
}
}
}
```
JavaScript
```javascript
var moveZeroes = function(nums) {

View File

@ -93,7 +93,7 @@ dp[i][3] = dp[i - 1][2];
综上分析,递推代码如下:
```CPP
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i];
dp[i][0] = max(dp[i - 1][0], max(dp[i - 1][3], dp[i - 1][1]) - prices[i]);
dp[i][1] = max(dp[i - 1][1], dp[i - 1][3]);
dp[i][2] = dp[i - 1][0] + prices[i];
dp[i][3] = dp[i - 1][2];

View File

@ -4,23 +4,22 @@
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
## 343. 整数拆分
# 343. 整数拆分
[力扣题目链接](https://leetcode-cn.com/problems/integer-break/)
给定一个正整数 n将其拆分为至少两个正整数的和并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
\解释: 2 = 1 + 1, 1 × 1 = 1。
* 输入: 2
* 输出: 1
* 解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
* 输入: 10
* 输出: 36
* 解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
* 说明: 你可以假设 n 不小于 2 且不大于 58。
## 思路
@ -193,7 +192,7 @@ public:
## 其他语言版本
Java
### Java
```Java
class Solution {
public int integerBreak(int n) {
@ -215,7 +214,7 @@ class Solution {
}
```
Python
### Python
```python
class Solution:
def integerBreak(self, n: int) -> int:
@ -229,7 +228,8 @@ class Solution:
dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
return dp[n]
```
Go
### Go
```golang
func integerBreak(n int) int {
/**
@ -259,7 +259,7 @@ func max(a,b int) int{
}
```
Javascript:
### Javascript
```Javascript
var integerBreak = function(n) {
let dp = new Array(n + 1).fill(0)
@ -274,5 +274,40 @@ var integerBreak = function(n) {
};
```
C:
```c
//初始化DP数组
int *initDP(int num) {
int* dp = (int*)malloc(sizeof(int) * (num + 1));
int i;
for(i = 0; i < num + 1; ++i) {
dp[i] = 0;
}
return dp;
}
//取三数最大值
int max(int num1, int num2, int num3) {
int tempMax = num1 > num2 ? num1 : num2;
return tempMax > num3 ? tempMax : num3;
}
int integerBreak(int n){
int *dp = initDP(n);
//初始化dp[2]为1
dp[2] = 1;
int i;
for(i = 3; i <= n; ++i) {
int j;
for(j = 1; j < i - 1; ++j) {
//取得上次循环:dp[i]原数相乘或j*dp[]i-j] 三数中的最大值
dp[i] = max(dp[i], j * (i - j), j * dp[i - j]);
}
}
return dp[n];
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -101,7 +101,6 @@ s[j] = tmp;
s[i] ^= s[j];
s[j] ^= s[i];
s[i] ^= s[j];
```
这道题目还是比较简单的,但是我正好可以通过这道题目说一说在刷题的时候,使用库函数的原则。
@ -201,6 +200,27 @@ var reverseString = function(s) {
};
```
TypeScript
```typescript
/**
Do not return anything, modify s in-place instead.
*/
function reverseString(s: string[]): void {
let length: number = s.length;
let left: number = 0,
right: number = length - 1;
let tempStr: string;
while (left < right) {
tempStr = s[left];
s[left] = s[right];
s[right] = tempStr;
left++;
right--;
}
};
```
Swift:
```swift
@ -233,6 +253,19 @@ void reverseString(char* s, int sSize){
}
```
C#
```csharp
public class Solution
{
public void ReverseString(char[] s)
{
for (int i = 0, j = s.Length - 1; i < j; i++, j--)
{
(s[i], s[j]) = (s[j], s[i]);
}
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -107,7 +107,7 @@ public:
}
}
// 找出前K个高频元素因为小顶堆先弹出的是最小的所以倒来输出到数组
// 找出前K个高频元素因为小顶堆先弹出的是最小的所以倒来输出到数组
vector<int> result(k);
for (int i = k - 1; i >= 0; i--) {
result[i] = pri_que.top().first;
@ -180,7 +180,7 @@ class Solution:
if len(pri_que) > k: #如果堆的大小大于了K则队列弹出保证堆的大小一直为k
heapq.heappop(pri_que)
#找出前K个高频元素因为小顶堆先弹出的是最小的所以倒来输出到数组
#找出前K个高频元素因为小顶堆先弹出的是最小的所以倒来输出到数组
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
@ -358,6 +358,22 @@ PriorityQueue.prototype.compare = function(index1, index2) {
}
```
TypeScript
```typescript
function topKFrequent(nums: number[], k: number): number[] {
const countMap: Map<number, number> = new Map();
for (let num of nums) {
countMap.set(num, (countMap.get(num) || 0) + 1);
}
// tS没有最小堆的数据结构所以直接对整个数组进行排序取前k个元素
return [...countMap.entries()]
.sort((a, b) => b[1] - a[1])
.slice(0, k)
.map(i => i[0]);
};
```
-----------------------

View File

@ -190,7 +190,33 @@ var intersection = function(nums1, nums2) {
};
```
TypeScript:
版本一(正常解法):
```typescript
function intersection(nums1: number[], nums2: number[]): number[] {
let resSet: Set<number> = new Set(),
nums1Set: Set<number> = new Set(nums1);
for (let i of nums2) {
if (nums1Set.has(i)) {
resSet.add(i);
}
}
return Array.from(resSet);
};
```
版本二(秀操作):
```typescript
function intersection(nums1: number[], nums2: number[]): number[] {
return Array.from(new Set(nums1.filter(i => nums2.includes(i))))
};
```
Swift
```swift
func intersection(_ nums1: [Int], _ nums2: [Int]) -> [Int] {
var set1 = Set<Int>()

View File

@ -264,6 +264,27 @@ var canConstruct = function(ransomNote, magazine) {
};
```
TypeScript:
```typescript
function canConstruct(ransomNote: string, magazine: string): boolean {
let helperArr: number[] = new Array(26).fill(0);
let base: number = 'a'.charCodeAt(0);
let index: number;
for (let i = 0, length = magazine.length; i < length; i++) {
helperArr[magazine[i].charCodeAt(0) - base]++;
}
for (let i = 0, length = ransomNote.length; i < length; i++) {
index = ransomNote[i].charCodeAt(0) - base;
helperArr[index]--;
if (helperArr[index] < 0) {
return false;
}
}
return true;
};
```
PHP:
```php

View File

@ -373,6 +373,54 @@ var sumOfLeftLeaves = function(root) {
```
## Swift
**递归法**
```swift
func sumOfLeftLeaves(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
let leftValue = sumOfLeftLeaves(root.left)
let rightValue = sumOfLeftLeaves(root.right)
var midValue: Int = 0
if root.left != nil && root.left?.left == nil && root.left?.right == nil {
midValue = root.left!.val
}
let sum = midValue + leftValue + rightValue
return sum
}
```
**迭代法**
```swift
func sumOfLeftLeaves(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var stack = Array<TreeNode>()
stack.append(root)
var sum = 0
while !stack.isEmpty {
let lastNode = stack.removeLast()
if lastNode.left != nil && lastNode.left?.left == nil && lastNode.left?.right == nil {
sum += lastNode.left!.val
}
if let right = lastNode.right {
stack.append(right)
}
if let left = lastNode.left {
stack.append(left)
}
}
return sum
}
```

View File

@ -112,7 +112,7 @@ vector<int> dp(10001, 0);
4. 确定遍历顺序
在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明如果使用一维dp数组物品遍历的for循环放在外层遍历背包的for循环放在内层且内层for循环倒遍历!
在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明如果使用一维dp数组物品遍历的for循环放在外层遍历背包的for循环放在内层且内层for循环倒遍历!
代码如下:

View File

@ -183,28 +183,22 @@ public:
```java
class Solution {
public int eraseOverlapIntervals(int[][] intervals) {
if (intervals.length < 2) return 0;
Arrays.sort(intervals, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[1] != o2[1]) {
return Integer.compare(o1[1],o2[1]);
} else {
return Integer.compare(o1[0],o2[0]);
}
}
Arrays.sort(intervals, (a, b) -> {
if (a[0] == a[0]) return a[1] - b[1];
return a[0] - b[0];
});
int count = 1;
int edge = intervals[0][1];
for (int i = 1; i < intervals.length; i++) {
if (edge <= intervals[i][0]){
count ++; //non overlap + 1
int count = 0;
int edge = Integer.MIN_VALUE;
for (int i = 0; i < intervals.length; i++) {
if (edge <= intervals[i][0]) {
edge = intervals[i][1];
} else {
count++;
}
}
return intervals.length - count;
return count;
}
}
```

View File

@ -239,5 +239,30 @@ int findMinArrowShots(int** points, int pointsSize, int* pointsColSize){
}
```
### Rust
```Rust
use std::cmp;
impl Solution {
pub fn find_min_arrow_shots(mut points: Vec<Vec<i32>>) -> i32 {
if points.is_empty() {
return 0;
}
points.sort_by_key(|point| point[0]);
let size = points.len();
let mut count = 1;
for i in 1..size {
if points[i][0] > points[i-1][1] {
count += 1;
} else {
points[i][1] = cmp::min(points[i][1], points[i-1][1]);
}
}
return count;
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -44,7 +44,7 @@ D = [ 0, 2]
1. 首先定义 一个unordered_mapkey放a和b两数之和value 放a和b两数之和出现的次数。
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也就是出现次数统计出来。
5. 最后返回统计值 count 就可以了
@ -192,8 +192,33 @@ var fourSumCount = function(nums1, nums2, nums3, nums4) {
};
```
TypeScript
```typescript
function fourSumCount(nums1: number[], nums2: number[], nums3: number[], nums4: number[]): number {
let helperMap: Map<number, number> = new Map();
let resNum: number = 0;
let tempVal: number | undefined;
for (let i of nums1) {
for (let j of nums2) {
tempVal = helperMap.get(i + j);
helperMap.set(i + j, tempVal ? tempVal + 1 : 1);
}
}
for (let k of nums3) {
for (let l of nums4) {
tempVal = helperMap.get(0 - (k + l));
if (tempVal) {
resNum += tempVal;
}
}
}
return resNum;
};
```
PHP:
```php
class Solution {
/**
@ -229,28 +254,24 @@ class Solution {
Swift
```swift
func fourSumCount(_ nums1: [Int], _ nums2: [Int], _ nums3: [Int], _ nums4: [Int]) -> Int {
// key:a+b的数值value:a+b数值出现次数
var map = [Int: Int]()
// 遍历nums1和nums2数组统计两个数组元素之和和出现的次数放到map中
for i in 0 ..< nums1.count {
for j in 0 ..< nums2.count {
let sum1 = nums1[i] + nums2[j]
map[sum1] = (map[sum1] ?? 0) + 1
// ab和: ab和出现次数
var countDic = [Int: Int]()
for a in nums1 {
for b in nums2 {
let key = a + b
countDic[key] = countDic[key, default: 0] + 1
}
}
// 统计a+b+c+d = 0 出现的次数
var res = 0
// 在遍历大num3和num4数组找到如果 0-(c+d) 在map中出现过的话就把map中key对应的value也就是出现次数统计出来。
for i in 0 ..< nums3.count {
for j in 0 ..< nums4.count {
let sum2 = nums3[i] + nums4[j]
let other = 0 - sum2
if map.keys.contains(other) {
res += map[other]!
}
// 通过-(c + d)作为key去累加ab和出现的次数
var result = 0
for c in nums3 {
for d in nums4 {
let key = -(c + d)
result += countDic[key, default: 0]
}
}
return res
return result
}
```

View File

@ -45,7 +45,7 @@
这里就要说一说next数组了next 数组记录的就是最长相同前后缀( [字符串KMP算法精讲](https://programmercarl.com/0028.实现strStr.html) 这里介绍了什么是前缀,什么是后缀,什么又是最长相同前后缀) 如果 next[len - 1] != -1则说明字符串有最长相同的前后缀就是字符串里的前缀子串和后缀子串相同的最长长度
最长相等前后缀的长度为next[len - 1] + 1。
最长相等前后缀的长度为next[len - 1] + 1。(这里的next数组是以统一减一的方式计算的因此需要+1)
数组长度为len。
@ -361,7 +361,65 @@ var repeatedSubstringPattern = function (s) {
};
```
TypeScript:
> 前缀表统一减一
```typescript
function repeatedSubstringPattern(s: string): boolean {
function getNext(str: string): number[] {
let next: number[] = [];
let j: number = -1;
next[0] = j;
for (let i = 1, length = str.length; i < length; i++) {
while (j >= 0 && str[i] !== str[j + 1]) {
j = next[j];
}
if (str[i] === str[j + 1]) {
j++;
}
next[i] = j;
}
return next;
}
let next: number[] = getNext(s);
let sLength: number = s.length;
let nextLength: number = next.length;
let suffixLength: number = next[nextLength - 1] + 1;
if (suffixLength > 0 && sLength % (sLength - suffixLength) === 0) return true;
return false;
};
```
> 前缀表不减一
```typescript
function repeatedSubstringPattern(s: string): boolean {
function getNext(str: string): number[] {
let next: number[] = [];
let j: number = 0;
next[0] = j;
for (let i = 1, length = str.length; i < length; i++) {
while (j > 0 && str[i] !== str[j]) {
j = next[j - 1];
}
if (str[i] === str[j]) {
j++;
}
next[i] = j;
}
return next;
}
let next: number[] = getNext(s);
let sLength: number = s.length;
let nextLength: number = next.length;
let suffixLength: number = next[nextLength - 1];
if (suffixLength > 0 && sLength % (sLength - suffixLength) === 0) return true;
return false;
};
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -289,7 +289,7 @@ func findTargetSumWays(nums []int, target int) int {
for _, v := range nums {
sum += v
}
if target > sum {
if abs(target) > sum {
return 0
}
if (sum+target)%2 == 1 {
@ -311,49 +311,12 @@ func findTargetSumWays(nums []int, target int) int {
}
return dp[bag]
}
```
> 更新版上一个跑不通了因为会存在bag 小于0的情况
```go
func findTargetSumWays(nums []int, target int) int {
//先转化为数学问题
//a-b=target
//a+b=sum
//a=(target+sum)/2
//求出sum
var sum int
for _,value:=range nums{
sum+=value
}
//如果sum<target或者 sum+target不是偶数因为a是int 或者两者之和小于0了
if sum<target||(sum+target)%2==1||(sum+target)<0{
return 0
}
//开始dp初始化
dp:=make([][]int,len(nums)+1)
for i:=0;i<=len(nums);i++{
tmp:=make([]int,(target+sum)/2+1)//背包容量
dp[i]=tmp
}
dp[0][0]=1//当背包容量为0且物品为0时填满背包就1种方法
for i:=0;i<len(nums)+1;i++{
if i==0{
continue
}
for j:=0;j<(target+sum)/2+1;j++{
if nums[i-1]<=j{//如果背包装的下
dp[i][j]=dp[i-1][j]+dp[i-1][j-nums[i-1]]
}else{
dp[i][j]=dp[i-1][j]
}
}
}
return dp[len(nums)][(target+sum)/2]
func abs(x int) int {
return int(math.Abs(float64(x)))
}
```
Javascript
```javascript
const findTargetSumWays = (nums, target) => {

View File

@ -245,6 +245,38 @@ var fib = function(n) {
};
```
### C
动态规划:
```c
int fib(int n){
//当n <= 1时返回n
if(n <= 1)
return n;
//动态开辟一个int数组大小为n+1
int *dp = (int *)malloc(sizeof(int) * (n + 1));
//设置0号位为01号为为1
dp[0] = 0;
dp[1] = 1;
//从前向后遍历数组(i=2; i <= n; ++i),下标为n时的元素为dp[i-1] + dp[i-2]
int i;
for(i = 2; i <= n; ++i) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
```
递归实现:
```c
int fib(int n){
//若n小于等于1返回n
if(n <= 1)
return n;
//否则返回fib(n-1) + fib(n-2)
return fib(n-1) + fib(n-2);
}
```
-----------------------

View File

@ -433,6 +433,74 @@ var findBottomLeftValue = function(root) {
};
```
## Swift
递归版本:
```swift
var maxLen = -1
var maxLeftValue = 0
func findBottomLeftValue_2(_ root: TreeNode?) -> Int {
traversal(root, 0)
return maxLeftValue
}
func traversal(_ root: TreeNode?, _ deep: Int) {
guard let root = root else {
return
}
if root.left == nil && root.right == nil {
if deep > maxLen {
maxLen = deep
maxLeftValue = root.val
}
return
}
if root.left != nil {
traversal(root.left, deep + 1)
}
if root.right != nil {
traversal(root.right, deep + 1)
}
return
}
```
层序遍历:
```swift
func findBottomLeftValue(_ root: TreeNode?) -> Int {
guard let root = root else {
return 0
}
var queue = [root]
var result = 0
while !queue.isEmpty {
let size = queue.count
for i in 0..<size {
let firstNode = queue.removeFirst()
if i == 0 {
result = firstNode.val
}
if let leftNode = firstNode.left {
queue.append(leftNode)
}
if let rightNode = firstNode.right {
queue.append(rightNode)
}
}
}
return result
}
```
-----------------------

View File

@ -252,6 +252,28 @@ var reverseStr = function(s, k) {
```
TypeScript
```typescript
function reverseStr(s: string, k: number): string {
let left: number, right: number;
let arr: string[] = s.split('');
let temp: string;
for (let i = 0, length = arr.length; i < length; i += 2 * k) {
left = i;
right = (i + k - 1) >= length ? length - 1 : i + k - 1;
while (left < right) {
temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
return arr.join('');
};
```
Swift:
```swift
@ -272,9 +294,21 @@ func reverseStr(_ s: String, _ k: Int) -> String {
}
```
C#
```csharp
public class Solution
{
public string ReverseStr(string s, int k)
{
Span<char> span = s.ToCharArray().AsSpan();
for (int i = 0; i < span.Length; i += 2 * k)
{
span[i + k < span.Length ? i..(i + k) : i..].Reverse();
}
return span.ToString();
}
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -18,6 +18,8 @@
## 思路
### 动态规划一
本题和[动态规划115.不同的子序列](https://programmercarl.com/0115.不同的子序列.html)相比,其实就是两个字符串都可以删除了,情况虽说复杂一些,但整体思路是不变的。
这次是两个字符串可以相互删了,这种题目也知道用动态规划的思路来解,动规五部曲,分析如下:
@ -98,6 +100,29 @@ public:
```
### 动态规划二
本题和[动态规划1143.最长公共子序列](https://programmercarl.com/1143.最长公共子序列.html)基本相同,只要求出两个字符串的最长公共子序列长度即可,那么除了最长公共子序列之外的字符都是必须删除的,最后用两个字符串的总长度减去两个最长公共子序列的长度就是删除的最少步数。
代码如下:
```CPP
class Solution {
public:
int minDistance(string word1, string word2) {
vector<vector<int>> dp(word1.size()+1, vector<int>(word2.size()+1, 0));
for (int i=1; i<=word1.size(); i++){
for (int j=1; j<=word2.size(); j++){
if (word1[i-1] == word2[j-1]) dp[i][j] = dp[i-1][j-1] + 1;
else dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
return word1.size()+word2.size()-dp[word1.size()][word2.size()]*2;
}
};
```
## 其他语言版本

View File

@ -401,6 +401,33 @@ struct TreeNode* constructMaximumBinaryTree(int* nums, int numsSize){
}
```
## Swift
```swift
func constructMaximumBinaryTree(_ nums: inout [Int]) -> TreeNode? {
return traversal(&nums, 0, nums.count)
}
func traversal(_ nums: inout [Int], _ left: Int, _ right: Int) -> TreeNode? {
if left >= right {
return nil
}
var maxValueIndex = left
for i in (left + 1)..<right {
if nums[i] > nums[maxValueIndex] {
maxValueIndex = i
}
}
let root = TreeNode(nums[maxValueIndex])
root.left = traversal(&nums, left, maxValueIndex)
root.right = traversal(&nums, maxValueIndex + 1, right)
return root
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -154,6 +154,8 @@ public:
Java
> 动态规划:
```java
/**
* 1.dp[i] 代表当前下标最大连续值
@ -180,6 +182,25 @@ Java
}
```
> 贪心法:
```Java
public static int findLengthOfLCIS(int[] nums) {
if (nums.length == 0) return 0;
int res = 1; // 连续子序列最少也是1
int count = 1;
for (int i = 0; i < nums.length - 1; i++) {
if (nums[i + 1] > nums[i]) { // 连续记录
count++;
} else { // 不连续count从头开始
count = 1;
}
if (count > res) res = count;
}
return res;
}
```
Python
> 动态规划:

View File

@ -68,7 +68,7 @@ for (int i = 0; i < n; i++) {
```cpp
vector<int> vec; // 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
for (int i = n - 1; i >= 0; i--) {
if (inDegree[edges[i][1]] == 2) {
vec.push_back(i);
@ -577,7 +577,7 @@ var findRedundantDirectedConnection = function(edges) {
inDegree[edges[i][1]]++; // 统计入度
}
let vec = [];// 记录入度为2的边如果有的话就两条边
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
// 找入度为2的节点所对应的边注意要倒,因为优先返回最后出现在二维数组中的答案
for (let i = n - 1; i >= 0; i--) {
if (inDegree[edges[i][1]] == 2) {
vec.push(i);

View File

@ -119,7 +119,7 @@ C++代码如下:
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
// 递
// 递
stack<int> st;
vector<int> result(T.size(), 0);
st.push(0);
@ -150,7 +150,7 @@ public:
class Solution {
public:
vector<int> dailyTemperatures(vector<int>& T) {
stack<int> st; // 递
stack<int> st; // 递
vector<int> result(T.size(), 0);
for (int i = 0; i < T.size(); i++) {
while (!st.empty() && T[i] > T[st.top()]) { // 注意栈不能为空
@ -178,7 +178,7 @@ public:
Java
```java
/**
* 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到
* 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到
* <p>
* 入站元素要和当前栈内栈首元素进行比较
* 若大于栈首则 则与元素下标做差

View File

@ -82,7 +82,7 @@ dp[1] = cost[1];
**但是稍稍有点难度的动态规划,其遍历顺序并不容易确定下来**
例如01背包都知道两个for循环一个for遍历物品嵌套一个for遍历背包容量那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢 以及在使用一维dp数组的时候遍历背包容量为什么要倒呢?
例如01背包都知道两个for循环一个for遍历物品嵌套一个for遍历背包容量那么为什么不是一个for遍历背包容量嵌套一个for遍历物品呢 以及在使用一维dp数组的时候遍历背包容量为什么要倒呢?
**这些都是遍历顺序息息相关。当然背包问题后续「代码随想录」都会重点讲解的!**
@ -266,5 +266,21 @@ var minCostClimbingStairs = function(cost) {
};
```
### C
```c
int minCostClimbingStairs(int* cost, int costSize){
//开辟dp数组大小为costSize
int *dp = (int *)malloc(sizeof(int) * costSize);
//初始化dp[0] = cost[0], dp[1] = cost[1]
dp[0] = cost[0], dp[1] = cost[1];
int i;
for(i = 2; i < costSize; ++i) {
dp[i] = (dp[i-1] < dp[i-2] ? dp[i-1] : dp[i-2]) + cost[i];
}
//选出倒数2层楼梯中较小的
return dp[i-1] < dp[i-2] ? dp[i-1] : dp[i-2];
}
```
-----------------------
<div align="center"><img src=https://code-thinking.cdn.bcebos.com/pics/01二维码一.jpg width=500> </img></div>

View File

@ -205,6 +205,42 @@ class Solution:
return self.get_string(s) == self.get_string(t)
pass
```
双指针
```python
class Solution:
def backspaceCompare(self, s: str, t: str) -> bool:
s_index, t_index = len(s) - 1, len(t) - 1
s_backspace, t_backspace = 0, 0 # 记录s,t的#数量
while s_index >= 0 or t_index >= 0: # 使用or以防长度不一致
while s_index >= 0: # 从后向前消除s的#
if s[s_index] == '#':
s_index -= 1
s_backspace += 1
else:
if s_backspace > 0:
s_index -= 1
s_backspace -= 1
else:
break
while t_index >= 0: # 从后向前消除t的#
if t[t_index] == '#':
t_index -= 1
t_backspace += 1
else:
if t_backspace > 0:
t_index -= 1
t_backspace -= 1
else:
break
if s_index >= 0 and t_index >= 0: # 后半部分#消除完了,接下来比较当前位的值
if s[s_index] != t[t_index]:
return False
elif s_index >= 0 or t_index >= 0: # 一个字符串找到了待比较的字符另一个没有返回False
return False
s_index -= 1
t_index -= 1
return True
```
### Go
@ -226,6 +262,51 @@ func backspaceCompare(s string, t string) bool {
return getString(s) == getString(t)
}
```
双指针
```go
func backspaceCompare(s string, t string) bool {
s_index, t_index := len(s) - 1, len(t) - 1
s_backspace, t_backspace := 0, 0 // 记录s,t的#数量
for s_index >= 0 || t_index >= 0 { // 使用or以防长度不一致
for s_index >= 0 { // 从后向前消除s的#
if s[s_index] == '#' {
s_index--
s_backspace++
} else {
if s_backspace > 0 {
s_index--
s_backspace--
} else {
break
}
}
}
for t_index >= 0 { // 从后向前消除t的#
if t[t_index] == '#' {
t_index--
t_backspace++
} else {
if t_backspace > 0 {
t_index--
t_backspace--
} else {
break
}
}
}
if s_index >= 0 && t_index >= 0 { // 后半部分#消除完了,接下来比较当前位的值
if s[s_index] != t[t_index] {
return false
}
} else if s_index >= 0 || t_index >= 0 { // 一个字符串找到了待比较的字符另一个没有返回false
return false
}
s_index--
t_index--
}
return true
}
```
### JavaScript

View File

@ -58,7 +58,7 @@ words[i] 由小写英文字母组成
先统计第一个字符串所有字符出现的次数,代码如下:
```
```cpp
int hash[26] = {0}; // 用来统计所有字符串里字符出现的最小频率
for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
hash[A[0][i] - 'a']++;
@ -71,7 +71,7 @@ for (int i = 0; i < A[0].size(); i++) { // 用第一个字符串给hash初始化
代码如下:
```
```cpp
int hashOtherStr[26] = {0}; // 统计除第一个字符串外字符的出现频率
for (int i = 1; i < A.size(); i++) {
memset(hashOtherStr, 0, 26 * sizeof(int));
@ -84,11 +84,11 @@ for (int i = 1; i < A.size(); i++) {
}
}
```
此时hash里统计着字符在所有字符串里出现的最小次数那么把hash转题目要求的输出格式就可以了。
此时hash里统计着字符在所有字符串里出现的最小次数那么把hash转题目要求的输出格式就可以了。
代码如下:
```
```cpp
// 将hash统计的字符次数转成输出形式
for (int i = 0; i < 26; i++) {
while (hash[i] != 0) { // 注意这里是while多个重复的字符

View File

@ -63,7 +63,7 @@
![1047.删除字符串中的所有相邻重复项](https://code-thinking.cdn.bcebos.com/gifs/1047.删除字符串中的所有相邻重复项.gif)
从栈中弹出剩余元素此时是字符串ac因为从栈里弹出的元素是倒的,所以在对字符串进行反转一下,就得到了最终的结果。
从栈中弹出剩余元素此时是字符串ac因为从栈里弹出的元素是倒的,所以在对字符串进行反转一下,就得到了最终的结果。
C++代码 :
@ -267,8 +267,32 @@ var removeDuplicates = function(s) {
};
```
TypeScript
```typescript
function removeDuplicates(s: string): string {
const helperStack: string[] = [];
let i: number = 0;
while (i < s.length) {
let top: string = helperStack[helperStack.length - 1];
if (top === s[i]) {
helperStack.pop();
} else {
helperStack.push(s[i]);
}
i++;
}
let res: string = '';
while (helperStack.length > 0) {
res = helperStack.pop() + res;
}
return res;
};
```
C:
方法一:使用栈
```c
char * removeDuplicates(char * s){
//求出字符串长度

View File

@ -87,7 +87,7 @@ vector<int> dp(15001, 0);
4. 确定遍历顺序
在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明如果使用一维dp数组物品遍历的for循环放在外层遍历背包的for循环放在内层且内层for循环倒遍历!
在[动态规划关于01背包问题你该了解这些滚动数组](https://programmercarl.com/背包理论基础01背包-2.html)中就已经说明如果使用一维dp数组物品遍历的for循环放在外层遍历背包的for循环放在内层且内层for循环倒遍历!
代码如下:

View File

@ -227,7 +227,23 @@ function TreeNode(val, left, right) {
}
```
TypeScript
```typescript
class TreeNode {
public val: number;
public left: TreeNode | null;
public right: TreeNode | null;
constructor(val?: number, left?: TreeNode, right?: TreeNode) {
this.val = val === undefined ? 0 : val;
this.left = left === undefined ? null : left;
this.right = right === undefined ? null : right;
}
}
```
Swift:
```Swift
class TreeNode<T> {
var value: T

View File

@ -454,6 +454,61 @@ var postorderTraversal = function(root, res = []) {
};
```
TypeScript:
```typescript
// 前序遍历(迭代法)
function preorderTraversal(root: TreeNode | null): number[] {
if (root === null) return [];
let res: number[] = [];
let helperStack: TreeNode[] = [];
let curNode: TreeNode = root;
helperStack.push(curNode);
while (helperStack.length > 0) {
curNode = helperStack.pop()!;
res.push(curNode.val);
if (curNode.right !== null) helperStack.push(curNode.right);
if (curNode.left !== null) helperStack.push(curNode.left);
}
return res;
};
// 中序遍历(迭代法)
function inorderTraversal(root: TreeNode | null): number[] {
let helperStack: TreeNode[] = [];
let res: number[] = [];
if (root === null) return res;
let curNode: TreeNode | null = root;
while (curNode !== null || helperStack.length > 0) {
if (curNode !== null) {
helperStack.push(curNode);
curNode = curNode.left;
} else {
curNode = helperStack.pop()!;
res.push(curNode.val);
curNode = curNode.right;
}
}
return res;
};
// 后序遍历(迭代法)
function postorderTraversal(root: TreeNode | null): number[] {
let helperStack: TreeNode[] = [];
let res: number[] = [];
let curNode: TreeNode;
if (root === null) return res;
helperStack.push(root);
while (helperStack.length > 0) {
curNode = helperStack.pop()!;
res.push(curNode.val);
if (curNode.left !== null) helperStack.push(curNode.left);
if (curNode.right !== null) helperStack.push(curNode.right);
}
return res.reverse();
};
```
Swift:
> 迭代法前序遍历

View File

@ -116,19 +116,19 @@ Java
```Java
// 前序遍历·递归·LC144_二叉树的前序遍历
class Solution {
ArrayList<Integer> preOrderReverse(TreeNode root) {
ArrayList<Integer> result = new ArrayList<Integer>();
preOrder(root, result);
public List<Integer> preorderTraversal(TreeNode root) {
List<Integer> result = new ArrayList<Integer>();
preorder(root, result);
return result;
}
void preOrder(TreeNode root, ArrayList<Integer> result) {
public void preorder(TreeNode root, List<Integer> result) {
if (root == null) {
return;
}
result.add(root.val); // 注意这一句
preOrder(root.left, result);
preOrder(root.right, result);
result.add(root.val);
preorder(root.left, result);
preorder(root.right, result);
}
}
// 中序遍历·递归·LC94_二叉树的中序遍历
@ -270,40 +270,6 @@ func postorderTraversal(root *TreeNode) (res []int) {
}
```
javaScript:
```js
前序遍历:
var preorderTraversal = function(root, res = []) {
if (!root) return res;
res.push(root.val);
preorderTraversal(root.left, res)
preorderTraversal(root.right, res)
return res;
};
中序遍历:
var inorderTraversal = function(root, res = []) {
if (!root) return res;
inorderTraversal(root.left, res);
res.push(root.val);
inorderTraversal(root.right, res);
return res;
};
后序遍历:
var postorderTraversal = function(root, res = []) {
if (!root) return res;
postorderTraversal(root.left, res);
postorderTraversal(root.right, res);
res.push(root.val);
return res;
};
```
Javascript版本
前序遍历:
@ -358,7 +324,51 @@ var postorderTraversal = function(root) {
};
```
TypeScript:
```typescript
// 前序遍历
function preorderTraversal(node: TreeNode | null): number[] {
function traverse(node: TreeNode | null, res: number[]): void {
if (node === null) return;
res.push(node.val);
traverse(node.left, res);
traverse(node.right, res);
}
const res: number[] = [];
traverse(node, res);
return res;
}
// 中序遍历
function inorderTraversal(node: TreeNode | null): number[] {
function traverse(node: TreeNode | null, res: number[]): void {
if (node === null) return;
traverse(node.left, res);
res.push(node.val);
traverse(node.right, res);
}
const res: number[] = [];
traverse(node, res);
return res;
}
// 后序遍历
function postorderTraversal(node: TreeNode | null): number[] {
function traverse(node: TreeNode | null, res: number[]): void {
if (node === null) return;
traverse(node.left, res);
traverse(node.right, res);
res.push(node.val);
}
const res: number[] = [];
traverse(node, res);
return res;
}
```
C:
```c
//前序遍历:
void preOrderTraversal(struct TreeNode* root, int* ret, int* returnSize) {

View File

@ -135,7 +135,6 @@ Markdown支持部分html例如这样
-----------------------
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
* B站视频[代码随想录](https://space.bilibili.com/525438321)

View File

@ -298,6 +298,33 @@ javaScript:
};
```
TypeScript
```typescript
function replaceSpace(s: string): string {
let arr: string[] = s.split('');
let spaceNum: number = 0;
let oldLength: number = arr.length;
for (let i = 0; i < oldLength; i++) {
if (arr[i] === ' ') {
spaceNum++;
}
}
arr.length = oldLength + 2 * spaceNum;
let cur: number = oldLength - 1;
for (let i = arr.length - 1; i >= 0; i--, cur--) {
if (arr[cur] !== ' ') {
arr[i] = arr[cur]
} else {
arr[i] = '0';
arr[--i] = '2';
arr[--i] = '%';
}
}
return arr.join('');
};
```
Swift:
```swift

View File

@ -209,6 +209,61 @@ var reverseLeftWords = function(s, n) {
};
```
版本二(在原字符串上操作):
```js
/**
* @param {string} s
* @param {number} n
* @return {string}
*/
var reverseLeftWords = function (s, n) {
/** Utils */
function reverseWords(strArr, start, end) {
let temp;
while (start < end) {
temp = strArr[start];
strArr[start] = strArr[end];
strArr[end] = temp;
start++;
end--;
}
}
/** Main code */
let strArr = s.split('');
let length = strArr.length;
reverseWords(strArr, 0, length - 1);
reverseWords(strArr, 0, length - n - 1);
reverseWords(strArr, length - n, length - 1);
return strArr.join('');
};
```
TypeScript
```typescript
function reverseLeftWords(s: string, n: number): string {
/** Utils */
function reverseWords(strArr: string[], start: number, end: number): void {
let temp: string;
while (start < end) {
temp = strArr[start];
strArr[start] = strArr[end];
strArr[end] = temp;
start++;
end--;
}
}
/** Main code */
let strArr: string[] = s.split('');
let length: number = strArr.length;
reverseWords(strArr, 0, length - 1);
reverseWords(strArr, 0, length - n - 1);
reverseWords(strArr, length - n, length - 1);
return strArr.join('');
};
```
Swift:
```swift

View File

@ -67,7 +67,7 @@ deque是一个双向队列只要封住一段只开通另一端就可以实
我们也可以指定vector为栈的底层实现初始化语句如下
```
```cpp
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
```
@ -77,7 +77,7 @@ std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
也可以指定list 为起底层实现初始化queue的语句如下
```
```cpp
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
```

View File

@ -3,11 +3,12 @@
<img src="https://code-thinking-1253855093.file.myqcloud.com/pics/20210924105952.png" width="1000"/>
</a>
<p align="center"><strong><a href="https://mp.weixin.qq.com/s/tqCxrMEU-ajQumL1i8im9A">参与本项目</a>,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!</strong></p>
# 动态规划关于01背包问题你该了解这些
这周我们正式开始讲解背包问题!
背包问题的经典资料当然是:背包九讲。在公众号「代码随想录」后台回复:背包九讲,就可以获得背包九讲的PDF
背包问题的经典资料当然是:背包九讲。在公众号「代码随想录」后台回复:背包九讲,就可以获得背包九讲的pdf
但说实话,背包九讲对于小白来说确实不太友好,看起来还是有点费劲的,而且都是伪代码理解起来也吃力。
@ -32,7 +33,7 @@ leetcode上没有纯01背包的问题都是01背包应用方面的题目
## 01 背包
N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i]得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
![动态规划-背包问题](https://img-blog.csdnimg.cn/20210117175428387.jpg)
@ -40,7 +41,7 @@ leetcode上没有纯01背包的问题都是01背包应用方面的题目
这样其实是没有从底向上去思考,而是习惯性想到了背包,那么暴力的解法应该是怎么样的呢?
每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是$O(2^n)$这里的n表示物品数量。
每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是$o(2^n)$这里的n表示物品数量。
**所以暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!**
@ -109,7 +110,7 @@ for (int j = 0 ; j < weight[0]; j++) { // 当然这一步如果把dp数组
dp[0][j] = 0;
}
// 正序遍历
for (int j = weight[0]; j <= bagWeight; j++) {
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
```
@ -135,8 +136,8 @@ dp[0][j] 和 dp[i][0] 都已经初始化了,那么其他下标应该初始化
```
// 初始化 dp
vector<vector<int>> dp(weight.size(), vector<int>(bagWeight + 1, 0));
for (int j = weight[0]; j <= bagWeight; j++) {
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
@ -160,7 +161,7 @@ for (int j = weight[0]; j <= bagWeight; j++) {
```
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
@ -174,7 +175,7 @@ for(int i = 1; i < weight.size(); i++) { // 遍历物品
```
// weight数组的大小 就是物品个数
for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
for(int i = 1; i < weight.size(); i++) { // 遍历物品
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
@ -219,32 +220,32 @@ dp[i-1][j]和dp[i - 1][j - weight[i]] 都在dp[i][j]的左上角方向(包括
主要就是自己没有动手推导一下dp数组的演变过程如果推导明白了代码写出来就算有问题只要把dp数组打印出来对比一下和自己推导的有什么差异很快就可以发现问题了。
## 完整C++测试代码
## 完整c++测试代码
```CPP
```cpp
void test_2_wei_bag_problem1() {
vector<int> weight = {1, 3, 4};
vector<int> value = {15, 20, 30};
int bagWeight = 4;
int bagweight = 4;
// 二维数组
vector<vector<int>> dp(weight.size(), vector<int>(bagWeight + 1, 0));
vector<vector<int>> dp(weight.size(), vector<int>(bagweight + 1, 0));
// 初始化
for (int j = weight[0]; j <= bagWeight; j++) {
for (int j = weight[0]; j <= bagweight; j++) {
dp[0][j] = value[0];
}
// weight数组的大小 就是物品个数
for(int i = 1; i < weight.size(); i++) { // 遍历物品
for(int j = 0; j <= bagWeight; j++) { // 遍历背包容量
for(int j = 0; j <= bagweight; j++) { // 遍历背包容量
if (j < weight[i]) dp[i][j] = dp[i - 1][j];
else dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i]);
}
}
cout << dp[weight.size() - 1][bagWeight] << endl;
cout << dp[weight.size() - 1][bagweight] << endl;
}
int main() {
@ -267,48 +268,45 @@ int main() {
## 其他语言版本
Java
### java
```java
public static void main(String[] args) {
public static void main(string[] args) {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagSize = 4;
testWeightBagProblem(weight, value, bagSize);
int bagsize = 4;
testweightbagproblem(weight, value, bagsize);
}
public static void testWeightBagProblem(int[] weight, int[] value, int bagSize){
int wLen = weight.length, value0 = 0;
public static void testweightbagproblem(int[] weight, int[] value, int bagsize){
int wlen = weight.length, value0 = 0;
//定义dp数组dp[i][j]表示背包容量为j时前i个物品能获得的最大价值
int[][] dp = new int[wLen + 1][bagSize + 1];
int[][] dp = new int[wlen + 1][bagsize + 1];
//初始化背包容量为0时能获得的价值都为0
for (int i = 0; i <= wLen; i++){
for (int i = 0; i <= wlen; i++){
dp[i][0] = value0;
}
//遍历顺序:先遍历物品,再遍历背包容量
for (int i = 1; i <= wLen; i++){
for (int j = 1; j <= bagSize; j++){
for (int i = 1; i <= wlen; i++){
for (int j = 1; j <= bagsize; j++){
if (j < weight[i - 1]){
dp[i][j] = dp[i - 1][j];
}else{
dp[i][j] = Math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
dp[i][j] = math.max(dp[i - 1][j], dp[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
//打印dp数组
for (int i = 0; i <= wLen; i++){
for (int j = 0; j <= bagSize; j++){
System.out.print(dp[i][j] + " ");
for (int i = 0; i <= wlen; i++){
for (int j = 0; j <= bagsize; j++){
system.out.print(dp[i][j] + " ");
}
System.out.print("\n");
system.out.print("\n");
}
}
```
Python
### python
```python
def test_2_wei_bag_problem1(bag_size, weight, value) -> int:
rows, cols = len(weight), bag_size + 1
@ -343,26 +341,26 @@ if __name__ == "__main__":
```
Go
### go
```go
func test_2_wei_bag_problem1(weight, value []int, bagWeight int) int {
func test_2_wei_bag_problem1(weight, value []int, bagweight int) int {
// 定义dp数组
dp := make([][]int, len(weight))
for i, _ := range dp {
dp[i] = make([]int, bagWeight+1)
dp[i] = make([]int, bagweight+1)
}
// 初始化
for j := bagWeight; j >= weight[0]; j-- {
for j := bagweight; j >= weight[0]; j-- {
dp[0][j] = dp[0][j-weight[0]] + value[0]
}
// 递推公式
for i := 1; i < len(weight); i++ {
//正序,也可以倒序
for j := weight[i];j<= bagWeight ; j++ {
for j := weight[i];j<= bagweight ; j++ {
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]]+value[i])
}
}
return dp[len(weight)-1][bagWeight]
return dp[len(weight)-1][bagweight]
}
func max(a,b int) int {
@ -379,19 +377,19 @@ func main() {
}
```
javaScript:
### javascript
```js
function testWeightBagProblem (wight, value, size) {
function testweightbagproblem (wight, value, size) {
const len = wight.length,
dp = Array.from({length: len + 1}).map(
() => Array(size + 1).fill(0)
dp = array.from({length: len + 1}).map(
() => array(size + 1).fill(0)
);
for(let i = 1; i <= len; i++) {
for(let j = 0; j <= size; j++) {
if(wight[i - 1] <= j) {
dp[i][j] = Math.max(
dp[i][j] = math.max(
dp[i - 1][j],
value[i - 1] + dp[i - 1][j - wight[i - 1]]
)

View File

@ -103,7 +103,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
为什么呢?
**倒遍历是为了保证物品i只被放入一次**。但如果一旦正序遍历了那么物品0就会被重复加入多次
**倒遍历是为了保证物品i只被放入一次**。但如果一旦正序遍历了那么物品0就会被重复加入多次
举一个例子物品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]
就是先算dp[2]
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数组历的时候不用倒呢?**
因为对于二维dpdp[i][j]都是通过上一层即dp[i - 1][j]计算而来本层的dp[i][j]并不会被覆盖!
@ -210,7 +210,7 @@ int main() {
## 其他语言版本
Java
### Java
```java
public static void main(String[] args) {
@ -240,7 +240,7 @@ Java
Python
### Python
```python
def test_1_wei_bag_problem():
weight = [1, 3, 4]
@ -260,7 +260,7 @@ def test_1_wei_bag_problem():
test_1_wei_bag_problem()
```
Go
### Go
```go
func test_1_wei_bag_problem(weight, value []int, bagWeight int) int {
// 定义 and 初始化
@ -292,7 +292,7 @@ func main() {
}
```
javaScript:
### javaScript
```js

View File

@ -52,7 +52,7 @@ for(int i = 0; i < weight.size(); i++) { // 遍历物品
```CPP
// 先遍历物品,再遍历背包
for(int i = 0; i < weight.size(); i++) { // 遍历物品
for(int j = weight[i]; j < bagWeight ; j++) { // 遍历背包容量
for(int j = weight[i]; j <= bagWeight ; j++) { // 遍历背包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
}
@ -183,11 +183,9 @@ private static void testCompletePack(){
int[] value = {15, 20, 30};
int bagWeight = 4;
int[] dp = new int[bagWeight + 1];
for (int i = 0; i < weight.length; i++){
for (int j = 1; j <= bagWeight; j++){
if (j - weight[i] >= 0){
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
for (int i = 0; i < weight.length; i++){ // 遍历物品
for (int j = weight[i]; j <= bagWeight; j++){ // 遍历背包容量
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
for (int maxValue : dp){
@ -201,8 +199,8 @@ private static void testCompletePackAnotherWay(){
int[] value = {15, 20, 30};
int bagWeight = 4;
int[] dp = new int[bagWeight + 1];
for (int i = 1; i <= bagWeight; i++){
for (int j = 0; j < weight.length; j++){
for (int i = 1; i <= bagWeight; i++){ // 遍历背包容量
for (int j = 0; j < weight.length; j++){ // 遍历物品
if (i - weight[j] >= 0){
dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]);
}

View File

@ -168,11 +168,47 @@ public class ListNode {
}
```
Python
JavaScript:
```javascript
class ListNode {
val;
next = null;
constructor(value) {
this.val = value;
this.next = null;
}
}
```
TypeScript:
```typescript
class ListNode {
public val: number;
public next: ListNode = null;
constructor(value: number) {
this.val = value;
this.next = null;
}
}
```
Python
```python
class ListNode:
def __init__(self, val, next=None):
self.val = val
self.next = next
```
Go
```go
type ListNode struct {
Val int
Next *ListNode
}
```

View File

@ -0,0 +1,41 @@
# 双指针,不计算链表长度
设置指向headA和headB的指针pa、pb分别遍历两个链表每次循环同时更新pa和pb。
* 当链表A遍历完之后即pa为空时将pa指向headB
* 当链表B遍历完之后即pa为空时将pb指向headA
* 当pa与pb相等时即指向同一个节点该节点即为相交起始节点。
* 若链表不相交则pa、pb同时为空时退出循环即如果链表不相交pa与pb在遍历过全部节点后同时指向结尾空节点此时退出循环返回空。
# 证明思路
设链表A不相交部分长度为a链表B不相交部分长度为b两个链表相交部分长度为c。<br>
在pa指向链表A时即pa为空之前pa经过链表A不相交部分和相交部分走过的长度为a+c<br>
pa指向链表B后在移动相交节点之前经过链表B不相交部分走过的长度为b总合为a+c+b。<br>
同理pb走过长度的总合为b+c+a。二者相等即pa与pb可同时到达相交起始节点。 <br>
该方法可避免计算具体链表长度。
```cpp
class Solution {
public:
ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {
//链表为空时,返回空指针
if(headA == nullptr || headB == nullptr) return nullptr;
ListNode* pa = headA;
ListNode* pb = headB;
//pa与pb在遍历过全部节点后,同时指向结尾空节点时退出循环
while(pa != nullptr || pb != nullptr){
//pa为空时将pa指向headB
if(pa == nullptr){
pa = headB;
}
//pa为空时将pb指向headA
if(pb == nullptr){
pb = headA;
}
//pa与pb相等时返回相交起始节点
if(pa == pb){
return pa;
}
pa = pa->next;
pb = pb->next;
}
return nullptr;
}
};
```

View File

@ -239,6 +239,43 @@ var getIntersectionNode = function(headA, headB) {
};
```
TypeScript
```typescript
function getIntersectionNode(headA: ListNode | null, headB: ListNode | null): ListNode | null {
let sizeA: number = 0,
sizeB: number = 0;
let curA: ListNode | null = headA,
curB: ListNode | null = headB;
while (curA) {
sizeA++;
curA = curA.next;
}
while (curB) {
sizeB++;
curB = curB.next;
}
curA = headA;
curB = headB;
if (sizeA < sizeB) {
[sizeA, sizeB] = [sizeB, sizeA];
[curA, curB] = [curB, curA];
}
let gap = sizeA - sizeB;
while (gap-- && curA) {
curA = curA.next;
}
while (curA && curB) {
if (curA === curB) {
return curA;
}
curA = curA.next;
curB = curB.next;
}
return null;
};
```
C
```c