forked from azl397985856/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' of https://github.com/azl397985856/leetcode
- Loading branch information
Showing
14 changed files
with
596 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
## 题目地址 | ||
https://leetcode-cn.com/problems/two-sum | ||
|
||
## 题目描述 | ||
``` | ||
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 | ||
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。 | ||
示例: | ||
给定 nums = [2, 7, 11, 15], target = 9 | ||
因为 nums[0] + nums[1] = 2 + 7 = 9 | ||
所以返回 [0, 1] | ||
``` | ||
## 思路 | ||
最容易想到的就是暴力枚举,我们可以利用两层 for 循环来遍历每个元素,并查找满足条件的目标元素。不过这样时间复杂度为 O(N^2),空间复杂度为 O(1),时间复杂度较高,我们要想办法进行优化。我们可以增加一个 Map 记录已经遍历过的数字及其对应的索引值。这样当遍历一个新数字的时候去 Map 里查询,target 与该数的差值是否已经在前面的数字中出现过。如果出现过,那么已经得出答案,就不必再往下执行了。 | ||
|
||
## 关键点 | ||
|
||
- 求和转换为求差 | ||
- 借助 Map 结构将数组中每个元素及其索引相互对应 | ||
- 以空间换时间,将查找时间从 O(N) 降低到 O(1) | ||
|
||
## 代码 | ||
* 语言支持:JS | ||
|
||
```js | ||
/** | ||
* @param {number[]} nums | ||
* @param {number} target | ||
* @return {number[]} | ||
*/ | ||
const twoSum = function (nums, target) { | ||
const map = new Map(); | ||
for (let i = 0; i < nums.length; i++) { | ||
const diff = target - nums[i]; | ||
if (map.has(diff)) { | ||
return [map.get(diff), i]; | ||
} | ||
map.set(nums[i], i); | ||
} | ||
} | ||
``` | ||
|
||
***复杂度分析*** | ||
|
||
- 时间复杂度:O(N) | ||
- 空间复杂度:O(N) |
113 changes: 113 additions & 0 deletions
113
problems/105.Construct-Binary-Tree-from-Preorder-and-Inorder-Traversal.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
## 问题地址/Problem URL | ||
|
||
https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ | ||
|
||
## 问题介绍/Problem Description | ||
|
||
Given preorder and inorder traversal of a tree, construct the binary tree. | ||
|
||
Note: | ||
You may assume that duplicates do not exist in the tree. | ||
|
||
For example, given | ||
|
||
```java | ||
preorder = [3,9,20,15,7] | ||
inorder = [9,3,15,20,7] | ||
``` | ||
|
||
Return the following binary tree: | ||
|
||
```bash | ||
3 | ||
/ \ | ||
9 20 | ||
/ \ | ||
15 7 | ||
``` | ||
|
||
## 思路/Thinking Path | ||
|
||
目标是构造二叉树。 | ||
|
||
构造二叉树需要根的值、左子树和右子树。 | ||
|
||
此问题可被抽象为:从前序遍历和中序遍历中找到根节点、左子树和右子树。 | ||
|
||
先找根: | ||
由前序遍历的性质,第`0`个节点为当前树的根节点。 | ||
再找左右子树: | ||
在中序遍历中找到这个根节点,设其下标为`i`。由中序遍历的性质,`0 ~ i-1` 是左子树的中序遍历,`i+1 ~ inorder.length-1`是右子树的中序遍历。 | ||
|
||
然后递归求解,终止条件是左右子树为`null`。 | ||
|
||
We are going to construct a binary tree from its preorder and inorder traversal. | ||
|
||
To build a binary tree, it requires us to creact a new `TreeNode` as the root with filling in the root value. And then, find its left child and right child recursively until the left or right child is `null`. | ||
|
||
Now this problem is abstracted as how to find the root node, left child and right child from the preorder traversal and inorder traversal. | ||
|
||
In preorder traversal, the first node (`preorder[0]`) is the root of current binary tree. In inorder traversal, find the location of this root which is `i`. The left sub-tree is `0 to i-1` and the right sub-tree is `i+1 to inorder.length-1` in inorder traversal. | ||
|
||
Then applying the previous operation to the left and right sub-trees. | ||
|
||
## 关键解析/Key Points | ||
|
||
如何在前序遍历的数组里找到左右子树的: | ||
- 根据前序遍历的定义可知,每个当前数组的第一个元素就是当前子树的根节点的值 | ||
- 在中序遍历数组中找到这个值,设其下标为`inRoot` | ||
- 当前中序遍历数组的起点`inStart`到`inRoot`之间就是左子树,其长度`leftChldLen`为`inRoot-inStart` | ||
- 当前中序遍历数组的终点`inEnd`和`inRoot`之间就是右子树 | ||
- 前序遍历和中序遍历中左子树的长度是相等的,所以在前序遍历数组中,根节点下标`preStart`往后数`leftChldLen`即为左子树的最后一个节点,其下标为`preStart+leftChldLen`,右子树的第一个节点下标为`preStart+leftChldLen+1`。 | ||
|
||
**PLEASE READ THE CODE BEFORE READING THIS PART** | ||
|
||
If you can't figure out how to get the index of the left and right child, please read this. | ||
|
||
- index of current node in preorder array is preStart(or whatever your call it), it's the root of a subtree. | ||
- according to the properties of preoder traversal, all right sub-tree nodes are behine all left sub-tree nodes. The length of left sub-tree can help us to divide left and right sub-trees. | ||
- the length of left sub-tree can be find in the inorder traversal. The location of current node is `inRoot`(or whatever your call it). The start index of current inorder array is `inStart`(or whatever your call it). So, the lenght of the left sub-tree is `leftChldLen = inRoot - inStart`. | ||
|
||
![explain](../assets/problems/105.index_explain.jpg) | ||
|
||
## 代码/Code | ||
|
||
- Java | ||
|
||
```java | ||
/** | ||
* Definition for a binary tree node. | ||
* public class TreeNode { | ||
* int val; | ||
* TreeNode left; | ||
* TreeNode right; | ||
* TreeNode(int x) { val = x; } | ||
* } | ||
*/ | ||
class Solution { | ||
public TreeNode buildTree(int[] preorder, int[] inorder) { | ||
if (preorder.length != inorder.length) return null; | ||
|
||
HashMap<Integer, Integer> map = new HashMap<> (); | ||
|
||
for (int i=0; i<inorder.length; i++) { | ||
map.put(inorder[i], i); | ||
} | ||
|
||
return helper(preorder, 0, preorder.length-1, inorder, 0, inorder.length-1, map); | ||
} | ||
|
||
public TreeNode helper(int[] preorder, int preStart, int preEnd, int[] inorder, int inStart, int inEnd, HashMap<Integer, Integer> map) { | ||
if (preStart>preEnd || inStart>inEnd) return null; | ||
|
||
TreeNode root = new TreeNode(preorder[prestart]); | ||
int inRoot = map.get(preorder[preStart]); | ||
int leftChldLen = inRoot - inStart; | ||
|
||
root.left = helper(preorder, preStart+1, preStart+leftChldLen, inorder, inStart, inRoot-1, map); | ||
root.left = helper(preorder, preStart+leftChldLen+1, preEnd, inorder, inRoot+1, inEnd, map); | ||
|
||
return root; | ||
} | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
## 题目地址 | ||
https://leetcode-cn.com/problems/letter-combinations-of-a-phone-number | ||
|
||
## 题目描述 | ||
``` | ||
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。 | ||
给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。 | ||
示例: | ||
输入:"23" | ||
输出:["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. | ||
说明: | ||
尽管上面的答案是按字典序排列的,但是你可以任意选择答案输出的顺序。 | ||
``` | ||
|
||
## 思路 | ||
使用回溯法进行求解,回溯是一种通过穷举所有可能情况来找到所有解的算法。如果一个候选解最后被发现并不是可行解,回溯算法会舍弃它,并在前面的一些步骤做出一些修改,并重新尝试找到可行解。究其本质,其实就是枚举。 | ||
|
||
如果没有更多的数字需要被输入,说明当前的组合已经产生。 | ||
|
||
如果还有数字需要被输入: | ||
- 遍历下一个数字所对应的所有映射的字母 | ||
- 将当前的字母添加到组合最后,也就是 str + tmp[r] | ||
|
||
## 关键点 | ||
利用回溯思想解题,在for循环中调用递归。 | ||
|
||
## 代码 | ||
* 语言支持:JS | ||
|
||
```js | ||
/** | ||
* @param {string} digits | ||
* @return {string[]} | ||
*/ | ||
const letterCombinations = function (digits) { | ||
if (!digits) { | ||
return []; | ||
} | ||
const len = digits.length; | ||
const map = new Map(); | ||
map.set('2', 'abc'); | ||
map.set('3', 'def'); | ||
map.set('4', 'ghi'); | ||
map.set('5', 'jkl'); | ||
map.set('6', 'mno'); | ||
map.set('7', 'pqrs'); | ||
map.set('8', 'tuv'); | ||
map.set('9', 'wxyz'); | ||
const result = []; | ||
|
||
function generate(i, str) { | ||
if (i == len) { | ||
result.push(str); | ||
return; | ||
} | ||
const tmp = map.get(digits[i]); | ||
for (let r = 0; r < tmp.length; r++) { | ||
generate(i + 1, str + tmp[r]); | ||
} | ||
} | ||
generate(0, ''); | ||
return result; | ||
}; | ||
``` | ||
|
||
***复杂度分析*** | ||
|
||
N + M 是输入数字的总数 | ||
|
||
- 时间复杂度:O(3^N * 4^M) | ||
- 空间复杂度:O(3^N * 4^M) | ||
|
Oops, something went wrong.