diff --git a/problems/0019.删除链表的倒数第N个节点.md b/problems/0019.删除链表的倒数第N个节点.md index a76575bb..f0ef2366 100644 --- a/problems/0019.删除链表的倒数第N个节点.md +++ b/problems/0019.删除链表的倒数第N个节点.md @@ -22,10 +22,12 @@ 输入:head = [1,2,3,4,5], n = 2 输出:[1,2,3,5] + 示例 2: 输入:head = [1], n = 1 输出:[] + 示例 3: 输入:head = [1,2], n = 1 @@ -192,16 +194,18 @@ func removeNthFromEnd(head *ListNode, n int) *ListNode { * @param {number} n * @return {ListNode} */ -var removeNthFromEnd = function(head, n) { - let ret = new ListNode(0, head), - slow = fast = ret; - while(n--) fast = fast.next; - while (fast.next !== null) { - fast = fast.next; - slow = slow.next - }; - slow.next = slow.next.next; - return ret.next; +var removeNthFromEnd = function (head, n) { + // 创建哨兵节点,简化解题逻辑 + let dummyHead = new ListNode(0, head); + let fast = dummyHead; + let slow = dummyHead; + while (n--) fast = fast.next; + while (fast.next !== null) { + slow = slow.next; + fast = fast.next; + } + slow.next = slow.next.next; + return dummyHead.next; }; ``` ### TypeScript: diff --git a/problems/0077.组合.md b/problems/0077.组合.md index 9bbb4455..3a271ff8 100644 --- a/problems/0077.组合.md +++ b/problems/0077.组合.md @@ -469,28 +469,58 @@ func dfs(n int, k int, start int) { ``` ### Javascript +未剪枝: + +```js +var combine = function (n, k) { + // 回溯法 + let result = [], + path = []; + let backtracking = (_n, _k, startIndex) => { + // 终止条件 + if (path.length === _k) { + result.push(path.slice()); + return; + } + // 循环本层集合元素 + for (let i = startIndex; i <= _n; i++) { + path.push(i); + // 递归 + backtracking(_n, _k, i + 1); + // 回溯操作 + path.pop(); + } + }; + backtracking(n, k, 1); + return result; +}; +``` 剪枝: ```javascript -let result = [] -let path = [] -var combine = function(n, k) { - result = [] - combineHelper(n, k, 1) - return result +var combine = function (n, k) { + // 回溯法 + let result = [], + path = []; + let backtracking = (_n, _k, startIndex) => { + // 终止条件 + if (path.length === _k) { + result.push(path.slice()); + return; + } + // 循环本层集合元素 + for (let i = startIndex; i <= _n - (_k - path.length) + 1; i++) { + path.push(i); + // 递归 + backtracking(_n, _k, i + 1); + // 回溯操作 + path.pop(); + } + }; + backtracking(n, k, 1); + return result; }; -const combineHelper = (n, k, startIndex) => { - if (path.length === k) { - result.push([...path]) - return - } - for (let i = startIndex; i <= n - (k - path.length) + 1; ++i) { - path.push(i) - combineHelper(n, k, i + 1) - path.pop() - } -} ``` ### TypeScript diff --git a/problems/0102.二叉树的层序遍历.md b/problems/0102.二叉树的层序遍历.md index ab6b07bf..421c5dd9 100644 --- a/problems/0102.二叉树的层序遍历.md +++ b/problems/0102.二叉树的层序遍历.md @@ -692,27 +692,29 @@ func levelOrderBottom(root *TreeNode) [][]int { #### Javascript: ```javascript -var levelOrderBottom = function(root) { - let res = [], queue = []; - queue.push(root); - while(queue.length && root!==null) { - // 存放当前层级节点数组 - let curLevel = []; - // 计算当前层级节点数量 - let length = queue.length; - while(length--) { - let node = queue.shift(); - // 把当前层节点存入curLevel数组 - curLevel.push(node.val); - // 把下一层级的左右节点存入queue队列 - node.left && queue.push(node.left); - node.right && queue.push(node.right); - } - // 从数组前头插入值,避免最后反转数组,减少运算时间 - res.unshift(curLevel); +var levelOrderBottom = function (root) { + let res = [], + queue = []; + queue.push(root); + while (queue.length && root !== null) { + // 存放当前层级节点数组 + let curLevel = []; + // 计算当前层级节点数量 + let length = queue.length; + while (length--) { + let node = queue.shift(); + // 把当前层节点存入curLevel数组 + curLevel.push(node.val); + // 把下一层级的左右节点存入queue队列 + node.left && queue.push(node.left); + node.right && queue.push(node.right); } - return res; + // 从数组前头插入值,避免最后反转数组,减少运算时间 + res.unshift(curLevel); + } + return res; }; + ``` #### TypeScript: @@ -1140,7 +1142,7 @@ impl Solution { ### 思路 -本题就是层序遍历的时候把一层求个总和在取一个均值。 +本题就是层序遍历的时候把一层求个总和再取一个均值。 C++代码: @@ -1295,26 +1297,26 @@ func averageOfLevels(root *TreeNode) []float64 { ```javascript var averageOfLevels = function(root) { - //层级平均值 - let res = [], queue = []; - queue.push(root); - - while(queue.length && root!==null) { - //每一层节点个数 - let length = queue.length; - //sum记录每一层的和 - let sum = 0; - for(let i=0; i < length; i++) { - let node = queue.shift(); - sum += node.val; - node.left && queue.push(node.left); - node.right && queue.push(node.right); - } - //每一层的平均值存入数组res - res.push(sum/length); + let res = [], + queue = []; + queue.push(root); + while (queue.length) { + // 每一层节点个数; + let lengthLevel = queue.length, + len = queue.length, + // sum记录每一层的和; + sum = 0; + while (lengthLevel--) { + const node = queue.shift(); + sum += node.val; + // 队列存放下一层节点 + node.left && queue.push(node.left); + node.right && queue.push(node.right); } - - return res; + // 求平均值 + res.push(sum / len); + } + return res; }; ``` @@ -1925,26 +1927,28 @@ func max(x, y int) int { #### Javascript: ```javascript -var largestValues = function(root) { - //使用层序遍历 - let res = [], queue = []; - queue.push(root); - - while(root !== null && queue.length) { - //设置max初始值就是队列的第一个元素 - let max = queue[0].val; - let length = queue.length; - while(length--) { - let node = queue.shift(); - max = max > node.val ? max : node.val; - node.left && queue.push(node.left); - node.right && queue.push(node.right); - } - //把每一层的最大值放到res数组 - res.push(max); - } - +var largestValues = function (root) { + let res = [], + queue = []; + queue.push(root); + if (root === null) { return res; + } + while (queue.length) { + let lengthLevel = queue.length, + // 初始值设为负无穷大 + max = -Infinity; + while (lengthLevel--) { + const node = queue.shift(); + // 在当前层中找到最大值 + max = Math.max(max, node.val); + // 找到下一层的节点 + node.left && queue.push(node.left); + node.right && queue.push(node.right); + } + res.push(max); + } + return res; }; ``` @@ -2805,21 +2809,23 @@ func maxDepth(root *TreeNode) int { * @param {TreeNode} root * @return {number} */ -var maxDepth = function(root) { - // 最大的深度就是二叉树的层数 - if (root === null) return 0; - let queue = [root]; - let height = 0; - while (queue.length) { - let n = queue.length; - height++; - for (let i=0; i= target) { - // 不断移动左指针,直到不能再缩小为止 - while (sum - nums[left] >= target) { - sum -= nums[left++]; - } - res = Math.min(res, right - left + 1); - } - right++; + let left: number = 0, + res: number = Infinity, + subLen: number = 0, + sum: number = 0; + for (let right: number = 0; right < nums.length; right++) { + sum += nums[right]; + while (sum >= target) { + subLen = right - left + 1; + res = Math.min(res, subLen); + sum -= nums[left]; + left++; } - return res === nums.length + 1 ? 0 : res; -}; + } + return res === Infinity ? 0 : res; +} ``` ### Swift: diff --git a/problems/0216.组合总和III.md b/problems/0216.组合总和III.md index 861b6c66..3d7f2d0c 100644 --- a/problems/0216.组合总和III.md +++ b/problems/0216.组合总和III.md @@ -417,6 +417,7 @@ func dfs(k, n int, start int, sum int) { ``` ### JavaScript +- 未剪枝: ```js /** @@ -424,32 +425,74 @@ func dfs(k, n int, start int, sum int) { * @param {number} n * @return {number[][]} */ -var combinationSum3 = function(k, n) { - let res = []; - let path = []; - let sum = 0; - const dfs = (path,index) => { - // 剪枝操作 - if (sum > n){ - return - } - if (path.length == k) { - if(sum == n){ - res.push([...path]); - return - } - } - for (let i = index; i <= 9 - (k-path.length) + 1;i++) { - path.push(i); - sum = sum + i; - index += 1; - dfs(path,index); - sum -= i - path.pop() - } +var combinationSum3 = function (k, n) { + // 回溯法 + let result = [], + path = []; + const backtracking = (_k, targetSum, sum, startIndex) => { + // 终止条件 + if (path.length === _k) { + if (sum === targetSum) { + result.push(path.slice()); + } + // 如果总和不相等,就直接返回 + return; } - dfs(path,1); - return res + + // 循环当前节点,因为只使用数字1到9,所以最大是9 + for (let i = startIndex; i <= 9; i++) { + path.push(i); + sum += i; + // 回调函数 + backtracking(_k, targetSum, sum, i + 1); + // 回溯 + sum -= i; + path.pop(); + } + }; + backtracking(k, n, 0, 1); + return result; +}; +``` + +- 剪枝: + +```js +/** + * @param {number} k + * @param {number} n + * @return {number[][]} + */ +var combinationSum3 = function (k, n) { + // 回溯法 + let result = [], + path = []; + const backtracking = (_k, targetSum, sum, startIndex) => { + if (sum > targetSum) { + return; + } + // 终止条件 + if (path.length === _k) { + if (sum === targetSum) { + result.push(path.slice()); + } + // 如果总和不相等,就直接返回 + return; + } + + // 循环当前节点,因为只使用数字1到9,所以最大是9 + for (let i = startIndex; i <= 9 - (_k - path.length) + 1; i++) { + path.push(i); + sum += i; + // 回调函数 + backtracking(_k, targetSum, sum, i + 1); + // 回溯 + sum -= i; + path.pop(); + } + }; + backtracking(k, n, 0, 1); + return result; }; ``` diff --git a/problems/二叉树的递归遍历.md b/problems/二叉树的递归遍历.md index 9b4b7bc8..2ce9831e 100644 --- a/problems/二叉树的递归遍历.md +++ b/problems/二叉树的递归遍历.md @@ -48,7 +48,7 @@ void traversal(TreeNode* cur, vector& vec) if (cur == NULL) return; ``` -3. **确定单层递归的逻辑**:前序遍历是中左右的循序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下: +3. **确定单层递归的逻辑**:前序遍历是中左右的顺序,所以在单层递归的逻辑,是要先取中节点的数值,代码如下: ```cpp vec.push_back(cur->val); // 中 @@ -290,52 +290,91 @@ func postorderTraversal(root *TreeNode) (res []int) { 前序遍历: ```Javascript var preorderTraversal = function(root) { - let res=[]; - const dfs=function(root){ - if(root===null)return ; - //先序遍历所以从父节点开始 - res.push(root.val); - //递归左子树 - dfs(root.left); - //递归右子树 - dfs(root.right); - } - //只使用一个参数 使用闭包进行存储结果 - dfs(root); - return res; +// 第一种 +// let res=[]; +// const dfs=function(root){ +// if(root===null)return ; +// //先序遍历所以从父节点开始 +// res.push(root.val); +// //递归左子树 +// dfs(root.left); +// //递归右子树 +// dfs(root.right); +// } +// //只使用一个参数 使用闭包进行存储结果 +// dfs(root); +// return res; +// 第二种 + return root + ? [ + // 前序遍历:中左右 + root.val, + // 递归左子树 + ...preorderTraversal(root.left), + // 递归右子树 + ...preorderTraversal(root.right), + ] + : []; }; ``` 中序遍历 ```javascript var inorderTraversal = function(root) { - let res=[]; - const dfs=function(root){ - if(root===null){ - return ; - } - dfs(root.left); - res.push(root.val); - dfs(root.right); - } - dfs(root); - return res; +// 第一种 + + // let res=[]; + // const dfs=function(root){ + // if(root===null){ + // return ; + // } + // dfs(root.left); + // res.push(root.val); + // dfs(root.right); + // } + // dfs(root); + // return res; + +// 第二种 + return root + ? [ + // 中序遍历:左中右 + // 递归左子树 + ...inorderTraversal(root.left), + root.val, + // 递归右子树 + ...inorderTraversal(root.right), + ] + : []; }; ``` 后序遍历 ```javascript var postorderTraversal = function(root) { - let res=[]; - const dfs=function(root){ - if(root===null){ - return ; - } - dfs(root.left); - dfs(root.right); - res.push(root.val); - } - dfs(root); - return res; + // 第一种 + // let res=[]; + // const dfs=function(root){ + // if(root===null){ + // return ; + // } + // dfs(root.left); + // dfs(root.right); + // res.push(root.val); + // } + // dfs(root); + // return res; + + // 第二种 + // 后续遍历:左右中 + return root + ? [ + // 递归左子树 + ...postorderTraversal(root.left), + // 递归右子树 + ...postorderTraversal(root.right), + root.val, + ] + : []; }; ``` diff --git a/problems/图论深搜理论基础.md b/problems/图论深搜理论基础.md index 9e8d90a3..27464aab 100644 --- a/problems/图论深搜理论基础.md +++ b/problems/图论深搜理论基础.md @@ -71,7 +71,7 @@ 有递归的地方就有回溯,那么回溯在哪里呢? -就地递归函数的下面,例如如下代码: +就递归函数的下面,例如如下代码: ```cpp void dfs(参数) { diff --git a/problems/数组总结篇.md b/problems/数组总结篇.md index 2a2681ab..f026e41b 100644 --- a/problems/数组总结篇.md +++ b/problems/数组总结篇.md @@ -16,7 +16,7 @@ **数组是存放在连续内存空间上的相同类型数据的集合。** -数组可以方便的通过下标索引的方式获取到下标下对应的数据。 +数组可以方便的通过下标索引的方式获取到下标对应的数据。 举一个字符数组的例子,如图所示: @@ -27,7 +27,7 @@ * **数组下标都是从0开始的。** * **数组内存空间的地址是连续的** -正是**因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。** +正是**因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。** 例如删除下标为3的元素,需要对下标为3的元素后面的所有元素都要做移动操作,如图所示: diff --git a/problems/数组理论基础.md b/problems/数组理论基础.md index 05451b3c..76e618c2 100644 --- a/problems/数组理论基础.md +++ b/problems/数组理论基础.md @@ -16,7 +16,7 @@ **数组是存放在连续内存空间上的相同类型数据的集合。** -数组可以方便的通过下标索引的方式获取到下标下对应的数据。 +数组可以方便的通过下标索引的方式获取到下标对应的数据。 举一个字符数组的例子,如图所示: @@ -29,7 +29,7 @@ * **数组下标都是从0开始的。** * **数组内存空间的地址是连续的** -正是**因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。** +正是**因为数组在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。** 例如删除下标为3的元素,需要对下标为3的元素后面的所有元素都要做移动操作,如图所示: