diff --git a/README.md b/README.md index c5149776..c1761f7b 100644 --- a/README.md +++ b/README.md @@ -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))的原创。引用本项目文章请注明出处,发现恶意抄袭或搬运,会动用法律武器维护自己的权益。让我们一起维护一个良好的技术创作环境!

diff --git a/problems/0001.两数之和.md b/problems/0001.两数之和.md index 37c95736..22b2e7eb 100644 --- a/problems/0001.两数之和.md +++ b/problems/0001.两数之和.md @@ -186,6 +186,24 @@ var twoSum = function (nums, target) { }; ``` +TypeScript: + +```typescript +function twoSum(nums: number[], target: number): number[] { + let helperMap: Map = 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 [] } ``` diff --git a/problems/0005.最长回文子串.md b/problems/0005.最长回文子串.md index f204a607..99458825 100644 --- a/problems/0005.最长回文子串.md +++ b/problems/0005.最长回文子串.md @@ -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; +} +``` -----------------------

diff --git a/problems/0015.三数之和.md b/problems/0015.三数之和.md index c78ab06d..e191eabc 100644 --- a/problems/0015.三数之和.md +++ b/problems/0015.三数之和.md @@ -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> ThreeSum(int[] nums) + { + var result = new List>(); + + 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 { n1, n2, n3 }); + + while (left < right && nums[left] == n2) + { + left++; + } + + while (left < right && nums[right] == n3) + { + right--; + } + } + } + } + + return result; + } +} +``` + -----------------------
diff --git a/problems/0018.四数之和.md b/problems/0018.四数之和.md index b94ebeef..bad258c1 100644 --- a/problems/0018.四数之和.md +++ b/problems/0018.四数之和.md @@ -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> FourSum(int[] nums, int target) + { + var result = new List>(); + + 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 { n1, n2, n3, n4 }); + + while (left < right && nums[left] == n3) + { + left++; + } + + while (left < right && nums[right] == n4) + { + right--; + } + } + } + } + } + + return result; + } +} +``` + -----------------------
diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index e041937f..813e9b02 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -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 { diff --git a/problems/0020.有效的括号.md b/problems/0020.有效的括号.md index 9e4046d4..95d62e42 100644 --- a/problems/0020.有效的括号.md +++ b/problems/0020.有效的括号.md @@ -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]() diff --git a/problems/0024.两两交换链表中的节点.md b/problems/0024.两两交换链表中的节点.md index 01abc7b4..bf1fd5e1 100644 --- a/problems/0024.两两交换链表中的节点.md +++ b/problems/0024.两两交换链表中的节点.md @@ -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 diff --git a/problems/0027.移除元素.md b/problems/0027.移除元素.md index 99990302..d69f2bcf 100644 --- a/problems/0027.移除元素.md +++ b/problems/0027.移除元素.md @@ -42,7 +42,7 @@ ![27.移除元素-暴力解法](https://tva1.sinaimg.cn/large/008eGmZEly1gntrc7x9tjg30du09m1ky.gif) -很明显暴力解法的时间复杂度是O(n^2),这道题目暴力解法在leetcode上是可以过的。 +很明显暴力解法的时间复杂度是$O(n^2)$,这道题目暴力解法在leetcode上是可以过的。 代码如下: diff --git a/problems/0028.实现strStr.md b/problems/0028.实现strStr.md index f0b56719..bbe5b80f 100644 --- a/problems/0028.实现strStr.md +++ b/problems/0028.实现strStr.md @@ -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 版本 > 前缀表统一减一 diff --git a/problems/0031.下一个排列.md b/problems/0031.下一个排列.md index 10ee0aaa..2219e24d 100644 --- a/problems/0031.下一个排列.md +++ b/problems/0031.下一个排列.md @@ -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()); } }; diff --git a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md index 2b96e41b..dfd90b82 100644 --- a/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md +++ b/problems/0034.在排序数组中查找元素的第一个和最后一个位置.md @@ -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 diff --git a/problems/0047.全排列II.md b/problems/0047.全排列II.md index 781f01c3..0cecac50 100644 --- a/problems/0047.全排列II.md +++ b/problems/0047.全排列II.md @@ -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; +} +``` + -----------------------
diff --git a/problems/0051.N皇后.md b/problems/0051.N皇后.md index 51415e88..7eb0d7a0 100644 --- a/problems/0051.N皇后.md +++ b/problems/0051.N皇后.md @@ -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= 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 diff --git a/problems/0052.N皇后II.md b/problems/0052.N皇后II.md index 78531798..67e439ca 100644 --- a/problems/0052.N皇后II.md +++ b/problems/0052.N皇后II.md @@ -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; +} +``` + -----------------------
diff --git a/problems/0054.螺旋矩阵.md b/problems/0054.螺旋矩阵.md index 3f85c607..ccf6f471 100644 --- a/problems/0054.螺旋矩阵.md +++ b/problems/0054.螺旋矩阵.md @@ -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 +``` -----------------------
diff --git a/problems/0059.螺旋矩阵II.md b/problems/0059.螺旋矩阵II.md index c7e91b4d..3f7a59ca 100644 --- a/problems/0059.螺旋矩阵II.md +++ b/problems/0059.螺旋矩阵II.md @@ -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 diff --git a/problems/0062.不同路径.md b/problems/0062.不同路径.md index e209abb1..efa85a03 100644 --- a/problems/0062.不同路径.md +++ b/problems/0062.不同路径.md @@ -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; +} +``` -----------------------
diff --git a/problems/0063.不同路径II.md b/problems/0063.不同路径II.md index 490b6b5c..8e82007e 100644 --- a/problems/0063.不同路径II.md +++ b/problems/0063.不同路径II.md @@ -4,7 +4,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 63. 不同路径 II +# 63. 不同路径 II [力扣题目链接](https://leetcode-cn.com/problems/unique-paths-ii/) @@ -22,23 +22,22 @@ ![](https://img-blog.csdnimg.cn/20210111204939971.png) -输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] -输出:2 +* 输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]] +* 输出:2 解释: -3x3 网格的正中间有一个障碍物。 -从左上角到右下角一共有 2 条不同的路径: -1. 向右 -> 向右 -> 向下 -> 向下 -2. 向下 -> 向下 -> 向右 -> 向右 +* 3x3 网格的正中间有一个障碍物。 +* 从左上角到右下角一共有 2 条不同的路径: + 1. 向右 -> 向右 -> 向下 -> 向下 + 2. 向下 -> 向下 -> 向右 -> 向右 示例 2: ![](https://img-blog.csdnimg.cn/20210111205857918.png) -输入:obstacleGrid = [[0,1],[0,0]] -输出:1 +* 输入:obstacleGrid = [[0,1],[0,0]] +* 输出:1 提示: - * m == obstacleGrid.length * n == obstacleGrid[i].length * 1 <= m, n <= 100 @@ -171,7 +170,7 @@ public: ## 其他语言版本 -Java: +### Java ```java class Solution { @@ -199,7 +198,7 @@ class Solution { ``` -Python: +### Python ```python class Solution: @@ -262,54 +261,41 @@ class Solution: ``` -Go: +### Go ```go func uniquePathsWithObstacles(obstacleGrid [][]int) int { - m,n:= len(obstacleGrid),len(obstacleGrid[0]) + m, n := len(obstacleGrid), len(obstacleGrid[0]) // 定义一个dp数组 - dp := make([][]int,m) - for i,_ := range dp { - dp[i] = make([]int,n) + dp := make([][]int, m) + for i, _ := range dp { + dp[i] = make([]int, n) } - // 初始化 - for i:=0;i diff --git a/problems/0070.爬楼梯.md b/problems/0070.爬楼梯.md index 97db670a..7f47a991 100644 --- a/problems/0070.爬楼梯.md +++ b/problems/0070.爬楼梯.md @@ -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]; +} +``` + -----------------------
diff --git a/problems/0096.不同的二叉搜索树.md b/problems/0096.不同的二叉搜索树.md index d4b8d024..41fcb8fe 100644 --- a/problems/0096.不同的二叉搜索树.md +++ b/problems/0096.不同的二叉搜索树.md @@ -4,7 +4,7 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 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]; +} +``` -----------------------
diff --git a/problems/0101.对称二叉树.md b/problems/0101.对称二叉树.md index b9dff99c..69bc41d3 100644 --- a/problems/0101.对称二叉树.md +++ b/problems/0101.对称二叉树.md @@ -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 +} +``` -----------------------
diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index 4fcbbff8..1fb9b633 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -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 +} +``` # 总结 diff --git a/problems/0104.二叉树的最大深度.md b/problems/0104.二叉树的最大深度.md index 85b41548..7038598b 100644 --- a/problems/0104.二叉树的最大深度.md +++ b/problems/0104.二叉树的最大深度.md @@ -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 +} +``` + -----------------------
diff --git a/problems/0106.从中序与后序遍历序列构造二叉树.md b/problems/0106.从中序与后序遍历序列构造二叉树.md index 487e4f7d..40d75983 100644 --- a/problems/0106.从中序与后序遍历序列构造二叉树.md +++ b/problems/0106.从中序与后序遍历序列构造二叉树.md @@ -684,7 +684,7 @@ class Solution: root.right = self.buildTree(preorder_right, inorder_right) return root -``` +``` 106.从中序与后序遍历序列构造二叉树 @@ -716,7 +716,7 @@ class Solution: root.right = self.buildTree(inorder_right, postorder_right) return root -``` +``` ## Go @@ -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 + } +} +``` + + + -----------------------
diff --git a/problems/0110.平衡二叉树.md b/problems/0110.平衡二叉树.md index c0914f05..9d43407a 100644 --- a/problems/0110.平衡二叉树.md +++ b/problems/0110.平衡二叉树.md @@ -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) + } +} +``` + -----------------------
diff --git a/problems/0111.二叉树的最小深度.md b/problems/0111.二叉树的最小深度.md index fc93d918..a439322a 100644 --- a/problems/0111.二叉树的最小深度.md +++ b/problems/0111.二叉树的最小深度.md @@ -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 +} +``` -----------------------
diff --git a/problems/0112.路径总和.md b/problems/0112.路径总和.md index 910e57c8..5ec8ffd0 100644 --- a/problems/0112.路径总和.md +++ b/problems/0112.路径总和.md @@ -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 +} +``` diff --git a/problems/0129.求根到叶子节点数字之和.md b/problems/0129.求根到叶子节点数字之和.md index d07d5244..980779c2 100644 --- a/problems/0129.求根到叶子节点数字之和.md +++ b/problems/0129.求根到叶子节点数字之和.md @@ -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; +} +``` -----------------------
diff --git a/problems/0131.分割回文串.md b/problems/0131.分割回文串.md index ec8ad61c..439ad8ea 100644 --- a/problems/0131.分割回文串.md +++ b/problems/0131.分割回文串.md @@ -587,5 +587,57 @@ func partition(_ s: String) -> [[String]] { } ``` +## Rust + +```rust +impl Solution { + pub fn partition(s: String) -> Vec> { + let mut ret = vec![]; + let mut path = vec![]; + let sub_str: Vec = s.chars().collect(); + + Self::backtracing(&sub_str, 0, &mut ret, &mut path); + + ret + } + + fn backtracing(sub_str: &Vec, start: usize, ret: &mut Vec>, path: &mut Vec) { + //如果起始位置大于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, 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 + } +} +``` -----------------------
diff --git a/problems/0142.环形链表II.md b/problems/0142.环形链表II.md index dfe042b8..e8ca950d 100644 --- a/problems/0142.环形链表II.md +++ b/problems/0142.环形链表II.md @@ -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? { diff --git a/problems/0143.重排链表.md b/problems/0143.重排链表.md index 4ea9cb97..00622623 100644 --- a/problems/0143.重排链表.md +++ b/problems/0143.重排链表.md @@ -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; +} +``` ----------------------- diff --git a/problems/0150.逆波兰表达式求值.md b/problems/0150.逆波兰表达式求值.md index 7f7b2f4c..f4dad823 100644 --- a/problems/0150.逆波兰表达式求值.md +++ b/problems/0150.逆波兰表达式求值.md @@ -133,39 +133,26 @@ public: java: ```Java -public class EvalRPN { - +class Solution { public int evalRPN(String[] tokens) { Deque 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 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 diff --git a/problems/0151.翻转字符串里的单词.md b/problems/0151.翻转字符串里的单词.md index 48324cd9..ead5fa12 100644 --- a/problems/0151.翻转字符串里的单词.md +++ b/problems/0151.翻转字符串里的单词.md @@ -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 diff --git a/problems/0202.快乐数.md b/problems/0202.快乐数.md index 2d678151..f0a46a40 100644 --- a/problems/0202.快乐数.md +++ b/problems/0202.快乐数.md @@ -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 = 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 { diff --git a/problems/0203.移除链表元素.md b/problems/0203.移除链表元素.md index 9d0ef91f..4e7bdd34 100644 --- a/problems/0203.移除链表元素.md +++ b/problems/0203.移除链表元素.md @@ -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. diff --git a/problems/0206.翻转链表.md b/problems/0206.翻转链表.md index 13ed753c..941928ba 100644 --- a/problems/0206.翻转链表.md +++ b/problems/0206.翻转链表.md @@ -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 diff --git a/problems/0209.长度最小的子数组.md b/problems/0209.长度最小的子数组.md index 7c13961d..dc1d9f18 100644 --- a/problems/0209.长度最小的子数组.md +++ b/problems/0209.长度最小的子数组.md @@ -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; +} +``` + -----------------------
diff --git a/problems/0222.完全二叉树的节点个数.md b/problems/0222.完全二叉树的节点个数.md index 754a6094..8d38bace 100644 --- a/problems/0222.完全二叉树的节点个数.md +++ b/problems/0222.完全二叉树的节点个数.md @@ -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 +} +``` + -----------------------
diff --git a/problems/0225.用队列实现栈.md b/problems/0225.用队列实现栈.md index fdb544a6..c45917db 100644 --- a/problems/0225.用队列实现栈.md +++ b/problems/0225.用队列实现栈.md @@ -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 { diff --git a/problems/0226.翻转二叉树.md b/problems/0226.翻转二叉树.md index ee1f5ddf..e6dbb709 100644 --- a/problems/0226.翻转二叉树.md +++ b/problems/0226.翻转二叉树.md @@ -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 +} +``` + -----------------------
diff --git a/problems/0232.用栈实现队列.md b/problems/0232.用栈实现队列.md index 4edba2f2..b00ffd80 100644 --- a/problems/0232.用栈实现队列.md +++ b/problems/0232.用栈实现队列.md @@ -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 { diff --git a/problems/0239.滑动窗口最大值.md b/problems/0239.滑动窗口最大值.md index d9788f63..adf3548c 100644 --- a/problems/0239.滑动窗口最大值.md +++ b/problems/0239.滑动窗口最大值.md @@ -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 { diff --git a/problems/0242.有效的字母异位词.md b/problems/0242.有效的字母异位词.md index cdcf39ce..52f8e667 100644 --- a/problems/0242.有效的字母异位词.md +++ b/problems/0242.有效的字母异位词.md @@ -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 { diff --git a/problems/0257.二叉树的所有路径.md b/problems/0257.二叉树的所有路径.md index cb837d87..4078320f 100644 --- a/problems/0257.二叉树的所有路径.md +++ b/problems/0257.二叉树的所有路径.md @@ -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 +} +``` -----------------------
diff --git a/problems/0283.移动零.md b/problems/0283.移动零.md index 13b9c26c..bb75a696 100644 --- a/problems/0283.移动零.md +++ b/problems/0283.移动零.md @@ -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) { diff --git a/problems/0309.最佳买卖股票时机含冷冻期.md b/problems/0309.最佳买卖股票时机含冷冻期.md index 18c940d4..2dc1e874 100644 --- a/problems/0309.最佳买卖股票时机含冷冻期.md +++ b/problems/0309.最佳买卖股票时机含冷冻期.md @@ -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]; diff --git a/problems/0343.整数拆分.md b/problems/0343.整数拆分.md index f616a606..b6182ed6 100644 --- a/problems/0343.整数拆分.md +++ b/problems/0343.整数拆分.md @@ -4,23 +4,22 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

-## 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]; +} +``` + -----------------------
diff --git a/problems/0344.反转字符串.md b/problems/0344.反转字符串.md index 28313839..58bada05 100644 --- a/problems/0344.反转字符串.md +++ b/problems/0344.反转字符串.md @@ -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]); + } + } +} +``` -----------------------
diff --git a/problems/0347.前K个高频元素.md b/problems/0347.前K个高频元素.md index e6ad751b..1d6a358b 100644 --- a/problems/0347.前K个高频元素.md +++ b/problems/0347.前K个高频元素.md @@ -107,7 +107,7 @@ public: } } - // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒叙来输出到数组 + // 找出前K个高频元素,因为小顶堆先弹出的是最小的,所以倒序来输出到数组 vector 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 = 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]); +}; +``` + ----------------------- diff --git a/problems/0349.两个数组的交集.md b/problems/0349.两个数组的交集.md index 812c4489..92342f17 100644 --- a/problems/0349.两个数组的交集.md +++ b/problems/0349.两个数组的交集.md @@ -190,7 +190,33 @@ var intersection = function(nums1, nums2) { }; ``` +TypeScript: + +版本一(正常解法): + +```typescript +function intersection(nums1: number[], nums2: number[]): number[] { + let resSet: Set = new Set(), + nums1Set: Set = 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() diff --git a/problems/0383.赎金信.md b/problems/0383.赎金信.md index 650f2a99..31e19b10 100644 --- a/problems/0383.赎金信.md +++ b/problems/0383.赎金信.md @@ -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 diff --git a/problems/0404.左叶子之和.md b/problems/0404.左叶子之和.md index ddbd100e..09272052 100644 --- a/problems/0404.左叶子之和.md +++ b/problems/0404.左叶子之和.md @@ -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() + 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 +} +``` diff --git a/problems/0416.分割等和子集.md b/problems/0416.分割等和子集.md index 23a285f8..45b8b416 100644 --- a/problems/0416.分割等和子集.md +++ b/problems/0416.分割等和子集.md @@ -112,7 +112,7 @@ vector 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循环倒序遍历! 代码如下: diff --git a/problems/0435.无重叠区间.md b/problems/0435.无重叠区间.md index 118360bc..389443d1 100644 --- a/problems/0435.无重叠区间.md +++ b/problems/0435.无重叠区间.md @@ -183,28 +183,22 @@ public: ```java class Solution { public int eraseOverlapIntervals(int[][] intervals) { - if (intervals.length < 2) return 0; - - Arrays.sort(intervals, new Comparator() { - @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; } } ``` diff --git a/problems/0452.用最少数量的箭引爆气球.md b/problems/0452.用最少数量的箭引爆气球.md index ebfe648f..33bbad55 100644 --- a/problems/0452.用最少数量的箭引爆气球.md +++ b/problems/0452.用最少数量的箭引爆气球.md @@ -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>) -> 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; + } +} +``` -----------------------
diff --git a/problems/0454.四数相加II.md b/problems/0454.四数相加II.md index 6853354c..a7c903eb 100644 --- a/problems/0454.四数相加II.md +++ b/problems/0454.四数相加II.md @@ -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 就可以了 @@ -139,7 +139,7 @@ class Solution(object): return count -``` +``` Go: ```go @@ -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 = 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 } ``` diff --git a/problems/0459.重复的子字符串.md b/problems/0459.重复的子字符串.md index fee9dee5..ccfb485c 100644 --- a/problems/0459.重复的子字符串.md +++ b/problems/0459.重复的子字符串.md @@ -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; +}; +``` -----------------------
diff --git a/problems/0494.目标和.md b/problems/0494.目标和.md index 1835f498..0faef4a5 100644 --- a/problems/0494.目标和.md +++ b/problems/0494.目标和.md @@ -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 { diff --git a/problems/0509.斐波那契数.md b/problems/0509.斐波那契数.md index d8020d83..c6ce76c0 100644 --- a/problems/0509.斐波那契数.md +++ b/problems/0509.斐波那契数.md @@ -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); +} +``` ----------------------- diff --git a/problems/0513.找树左下角的值.md b/problems/0513.找树左下角的值.md index 99f42d34..84ed3932 100644 --- a/problems/0513.找树左下角的值.md +++ b/problems/0513.找树左下角的值.md @@ -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..= 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 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(); + } +} +``` -----------------------
diff --git a/problems/0583.两个字符串的删除操作.md b/problems/0583.两个字符串的删除操作.md index d2f7d84b..53c1a125 100644 --- a/problems/0583.两个字符串的删除操作.md +++ b/problems/0583.两个字符串的删除操作.md @@ -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> dp(word1.size()+1, vector(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; + } +}; + +``` + ## 其他语言版本 diff --git a/problems/0654.最大二叉树.md b/problems/0654.最大二叉树.md index b4679c7d..44c74f89 100644 --- a/problems/0654.最大二叉树.md +++ b/problems/0654.最大二叉树.md @@ -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).. nums[maxValueIndex] { + maxValueIndex = i + } + } + + let root = TreeNode(nums[maxValueIndex]) + + root.left = traversal(&nums, left, maxValueIndex) + root.right = traversal(&nums, maxValueIndex + 1, right) + return root +} +``` + + -----------------------
diff --git a/problems/0674.最长连续递增序列.md b/problems/0674.最长连续递增序列.md index 98e09bf8..51d04e92 100644 --- a/problems/0674.最长连续递增序列.md +++ b/problems/0674.最长连续递增序列.md @@ -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: > 动态规划: diff --git a/problems/0685.冗余连接II.md b/problems/0685.冗余连接II.md index de62432c..d96d4912 100644 --- a/problems/0685.冗余连接II.md +++ b/problems/0685.冗余连接II.md @@ -68,7 +68,7 @@ for (int i = 0; i < n; i++) { ```cpp vector 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); diff --git a/problems/0739.每日温度.md b/problems/0739.每日温度.md index d025e73c..d7489028 100644 --- a/problems/0739.每日温度.md +++ b/problems/0739.每日温度.md @@ -119,7 +119,7 @@ C++代码如下: class Solution { public: vector dailyTemperatures(vector& T) { - // 递减栈 + // 递增栈 stack st; vector result(T.size(), 0); st.push(0); @@ -150,7 +150,7 @@ public: class Solution { public: vector dailyTemperatures(vector& T) { - stack st; // 递减栈 + stack st; // 递增栈 vector 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 /** - * 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到笑 + * 单调栈,栈内顺序要么从大到小 要么从小到大,本题从大到小 *

* 入站元素要和当前栈内栈首元素进行比较 * 若大于栈首则 则与元素下标做差 diff --git a/problems/0746.使用最小花费爬楼梯.md b/problems/0746.使用最小花费爬楼梯.md index a146cc8b..e94e4d24 100644 --- a/problems/0746.使用最小花费爬楼梯.md +++ b/problems/0746.使用最小花费爬楼梯.md @@ -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]; +} +``` -----------------------

diff --git a/problems/0844.比较含退格的字符串.md b/problems/0844.比较含退格的字符串.md index 5d629a8c..00d52e42 100644 --- a/problems/0844.比较含退格的字符串.md +++ b/problems/0844.比较含退格的字符串.md @@ -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 diff --git a/problems/1002.查找常用字符.md b/problems/1002.查找常用字符.md index 08e7ec3d..7c5566d3 100644 --- a/problems/1002.查找常用字符.md +++ b/problems/1002.查找常用字符.md @@ -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,多个重复的字符 diff --git a/problems/1047.删除字符串中的所有相邻重复项.md b/problems/1047.删除字符串中的所有相邻重复项.md index 755520f3..9a0bb1c1 100644 --- a/problems/1047.删除字符串中的所有相邻重复项.md +++ b/problems/1047.删除字符串中的所有相邻重复项.md @@ -63,7 +63,7 @@ ![1047.删除字符串中的所有相邻重复项](https://code-thinking.cdn.bcebos.com/gifs/1047.删除字符串中的所有相邻重复项.gif) -从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒叙的,所以在对字符串进行反转一下,就得到了最终的结果。 +从栈中弹出剩余元素,此时是字符串ac,因为从栈里弹出的元素是倒序的,所以在对字符串进行反转一下,就得到了最终的结果。 C++代码 : @@ -267,8 +267,32 @@ var removeDuplicates = function(s) { }; ``` +TypeScript: + +```typescript +function removeDuplicates(s: string): string { + const helperStack: string[] = []; + let i: number = 0; + while (i < s.length) { + let top: string = helperStack[helperStack.length - 1]; + if (top === s[i]) { + helperStack.pop(); + } else { + helperStack.push(s[i]); + } + i++; + } + let res: string = ''; + while (helperStack.length > 0) { + res = helperStack.pop() + res; + } + return res; +}; +``` + C: 方法一:使用栈 + ```c char * removeDuplicates(char * s){ //求出字符串长度 diff --git a/problems/1049.最后一块石头的重量II.md b/problems/1049.最后一块石头的重量II.md index 975968de..d64e7e56 100644 --- a/problems/1049.最后一块石头的重量II.md +++ b/problems/1049.最后一块石头的重量II.md @@ -87,7 +87,7 @@ vector 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循环倒序遍历! 代码如下: diff --git a/problems/二叉树理论基础.md b/problems/二叉树理论基础.md index cc899850..009e8276 100644 --- a/problems/二叉树理论基础.md +++ b/problems/二叉树理论基础.md @@ -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 { var value: T diff --git a/problems/二叉树的迭代遍历.md b/problems/二叉树的迭代遍历.md index 4cb94cb5..ba38726b 100644 --- a/problems/二叉树的迭代遍历.md +++ b/problems/二叉树的迭代遍历.md @@ -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: > 迭代法前序遍历 diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 45b576e7..c481fd11 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -116,19 +116,19 @@ Java: ```Java // 前序遍历·递归·LC144_二叉树的前序遍历 class Solution { - ArrayList preOrderReverse(TreeNode root) { - ArrayList result = new ArrayList(); - preOrder(root, result); + public List preorderTraversal(TreeNode root) { + List result = new ArrayList(); + preorder(root, result); return result; } - void preOrder(TreeNode root, ArrayList result) { + public void preorder(TreeNode root, List 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) { diff --git a/problems/前序/程序员写文档工具.md b/problems/前序/程序员写文档工具.md index b76fb036..e4193c42 100644 --- a/problems/前序/程序员写文档工具.md +++ b/problems/前序/程序员写文档工具.md @@ -135,7 +135,6 @@ Markdown支持部分html,例如这样 - ----------------------- * 作者微信:[程序员Carl](https://mp.weixin.qq.com/s/b66DFkOp8OOxdZC_xLZxfw) * B站视频:[代码随想录](https://space.bilibili.com/525438321) diff --git a/problems/剑指Offer05.替换空格.md b/problems/剑指Offer05.替换空格.md index d0f382c8..530545fb 100644 --- a/problems/剑指Offer05.替换空格.md +++ b/problems/剑指Offer05.替换空格.md @@ -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 diff --git a/problems/剑指Offer58-II.左旋转字符串.md b/problems/剑指Offer58-II.左旋转字符串.md index c391d661..61391274 100644 --- a/problems/剑指Offer58-II.左旋转字符串.md +++ b/problems/剑指Offer58-II.左旋转字符串.md @@ -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 diff --git a/problems/栈与队列理论基础.md b/problems/栈与队列理论基础.md index b9811b29..44fcbdd5 100644 --- a/problems/栈与队列理论基础.md +++ b/problems/栈与队列理论基础.md @@ -67,7 +67,7 @@ deque是一个双向队列,只要封住一段,只开通另一端就可以实 我们也可以指定vector为栈的底层实现,初始化语句如下: -``` +```cpp std::stack > third; // 使用vector为底层容器的栈 ``` @@ -77,7 +77,7 @@ std::stack > third; // 使用vector为底层容器的栈 也可以指定list 为起底层实现,初始化queue的语句如下: -``` +```cpp std::queue> third; // 定义以list为底层容器的队列 ``` diff --git a/problems/背包理论基础01背包-1.md b/problems/背包理论基础01背包-1.md index 4367aff9..6ff32017 100644 --- a/problems/背包理论基础01背包-1.md +++ b/problems/背包理论基础01背包-1.md @@ -3,11 +3,12 @@

参与本项目,贡献其他语言版本的代码,拥抱开源,让更多学习算法的小伙伴们收益!

+ # 动态规划:关于01背包问题,你该了解这些! 这周我们正式开始讲解背包问题! -背包问题的经典资料当然是:背包九讲。在公众号「代码随想录」后台回复:背包九讲,就可以获得背包九讲的PDF。 +背包问题的经典资料当然是:背包九讲。在公众号「代码随想录」后台回复:背包九讲,就可以获得背包九讲的pdf。 但说实话,背包九讲对于小白来说确实不太友好,看起来还是有点费劲的,而且都是伪代码理解起来也吃力。 @@ -32,7 +33,7 @@ leetcode上没有纯01背包的问题,都是01背包应用方面的题目, ## 01 背包 -有N件物品和一个最多能背重量为W 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 +有n件物品和一个最多能背重量为w 的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。**每件物品只能用一次**,求解将哪些物品装入背包里物品价值总和最大。 ![动态规划-背包问题](https://img-blog.csdnimg.cn/20210117175428387.jpg) @@ -40,7 +41,7 @@ leetcode上没有纯01背包的问题,都是01背包应用方面的题目, 这样其实是没有从底向上去思考,而是习惯性想到了背包,那么暴力的解法应该是怎么样的呢? -每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是$O(2^n)$,这里的n表示物品数量。 +每一件物品其实只有两个状态,取或者不取,所以可以使用回溯法搜索出所有的情况,那么时间复杂度就是$o(2^n)$,这里的n表示物品数量。 **所以暴力的解法是指数级别的时间复杂度。进而才需要动态规划的解法来进行优化!** @@ -109,7 +110,7 @@ for (int j = 0 ; j < weight[0]; j++) { // 当然这一步,如果把dp数组 dp[0][j] = 0; } // 正序遍历 -for (int j = weight[0]; j <= bagWeight; j++) { +for (int j = weight[0]; j <= bagweight; j++) { dp[0][j] = value[0]; } ``` @@ -135,8 +136,8 @@ dp[0][j] 和 dp[i][0] 都已经初始化了,那么其他下标应该初始化 ``` // 初始化 dp -vector> dp(weight.size(), vector(bagWeight + 1, 0)); -for (int j = weight[0]; j <= bagWeight; j++) { +vector> dp(weight.size(), vector(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 weight = {1, 3, 4}; vector value = {15, 20, 30}; - int bagWeight = 4; + int bagweight = 4; // 二维数组 - vector> dp(weight.size(), vector(bagWeight + 1, 0)); + vector> dp(weight.size(), vector(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]] ) diff --git a/problems/背包理论基础01背包-2.md b/problems/背包理论基础01背包-2.md index 7f646f06..dabdfb2d 100644 --- a/problems/背包理论基础01背包-2.md +++ b/problems/背包理论基础01背包-2.md @@ -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 diff --git a/problems/背包问题理论基础完全背包.md b/problems/背包问题理论基础完全背包.md index 3cc8557c..cea69c72 100644 --- a/problems/背包问题理论基础完全背包.md +++ b/problems/背包问题理论基础完全背包.md @@ -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]); } diff --git a/problems/链表理论基础.md b/problems/链表理论基础.md index 02b7029e..a4fefa2b 100644 --- a/problems/链表理论基础.md +++ b/problems/链表理论基础.md @@ -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 +} +``` diff --git a/problems/面试题 02.07. 解法更新.md b/problems/面试题 02.07. 解法更新.md new file mode 100644 index 00000000..6115d02e --- /dev/null +++ b/problems/面试题 02.07. 解法更新.md @@ -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。
+在pa指向链表A时,即pa为空之前,pa经过链表A不相交部分和相交部分,走过的长度为a+c;
+pa指向链表B后,在移动相交节点之前经过链表B不相交部分,走过的长度为b,总合为a+c+b。
+同理,pb走过长度的总合为b+c+a。二者相等,即pa与pb可同时到达相交起始节点。
+该方法可避免计算具体链表长度。 +```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; + } +}; +``` diff --git a/problems/面试题02.07.链表相交.md b/problems/面试题02.07.链表相交.md index e8198aa0..dd91f069 100644 --- a/problems/面试题02.07.链表相交.md +++ b/problems/面试题02.07.链表相交.md @@ -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