mirror of
https://github.com/youngyangyang04/leetcode-master.git
synced 2025-07-10 20:40:39 +08:00
Merge branch 'youngyangyang04:master' into master
This commit is contained in:
@ -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">
|
||||
|
@ -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 []
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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]()
|
||||
|
@ -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
|
||||
|
@ -42,7 +42,7 @@
|
||||
|
||||

|
||||
|
||||
很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。
|
||||
很明显暴力解法的时间复杂度是$O(n^2)$,这道题目暴力解法在leetcode上是可以过的。
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -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 版本
|
||||
|
||||
> 前缀表统一减一
|
||||
|
@ -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());
|
||||
}
|
||||
};
|
||||
|
@ -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没有被赋值的情况;这里不能赋值-1,target = 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
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
//从0,0到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>
|
||||
|
@ -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 @@
|
||||
|
||||

|
||||
|
||||
输入: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:
|
||||
|
||||

|
||||
|
||||
输入: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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
# 总结
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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? {
|
||||
|
@ -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;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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>
|
||||
|
@ -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) {
|
||||
|
@ -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];
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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]);
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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>()
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
@ -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循环倒序遍历!
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -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>
|
||||
|
@ -44,7 +44,7 @@ D = [ 0, 2]
|
||||
|
||||
1. 首先定义 一个unordered_map,key放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
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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) => {
|
||||
|
@ -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号位为0,1号为为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);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
## 其他语言版本
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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:
|
||||
|
||||
> 动态规划:
|
||||
|
@ -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);
|
||||
|
@ -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>
|
||||
* 入站元素要和当前栈内栈首元素进行比较
|
||||
* 若大于栈首则 则与元素下标做差
|
||||
|
@ -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>
|
||||
|
@ -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
|
||||
|
@ -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,多个重复的字符
|
||||
|
@ -63,7 +63,7 @@
|
||||
|
||||

|
||||
|
||||
从栈中弹出剩余元素,此时是字符串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){
|
||||
//求出字符串长度
|
||||
|
@ -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循环倒序遍历!
|
||||
|
||||
代码如下:
|
||||
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
||||
> 迭代法前序遍历
|
||||
|
@ -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) {
|
||||
|
@ -135,7 +135,6 @@ Markdown支持部分html,例如这样
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
* 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw)
|
||||
* B站视频:[代码随想录](https://space.bilibili.com/525438321)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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为底层容器的队列
|
||||
```
|
||||
|
||||
|
@ -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] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。
|
||||
|
||||

|
||||
|
||||
@ -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]]
|
||||
)
|
||||
|
@ -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数组历的时候不用倒序呢?**
|
||||
|
||||
因为对于二维dp,dp[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
|
||||
|
||||
|
@ -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]);
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
41
problems/面试题 02.07. 解法更新.md
Normal file
41
problems/面试题 02.07. 解法更新.md
Normal 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;
|
||||
}
|
||||
};
|
||||
```
|
@ -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
|
||||
|
Reference in New Issue
Block a user