auto commit

This commit is contained in:
CyC2018
2018-07-26 23:12:25 +08:00
parent 8a77f76a2c
commit 41176bb717
7 changed files with 103 additions and 61 deletions

View File

@ -90,12 +90,20 @@
## 题目描述
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。例如,如果输入长度为 7 的数组 {2, 3, 1, 0, 2, 5},那么对应的输出是第一个重复的数字 2。
在一个长度为 n 的数组里的所有数字都在 0 到 n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字是重复的,也不知道每个数字重复几次。请找出数组中任意一个重复的数字。
要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
```html
Input:
{2, 3, 1, 0, 2, 5}
Output:
2
```
## 解题思路
要求复杂度为 O(N) + O(1),也就是时间复杂度 O(N),空间复杂度 O(1)。因此不能使用排序的方法,也不能使用额外的标记数组。牛客网讨论区这一题的首票答案使用 nums[i] + length 来将元素标记,这么做会有加法溢出问题。
这种数组元素在 [0, n-1] 范围内的问题,可以将值为 i 的元素放到第 i 个位置上。
以 (2, 3, 1, 0, 2, 5) 为例:
@ -158,7 +166,11 @@ Given target = 20, return false.
## 解题思路
从右上角开始查找。因为矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
从右上角开始查找。矩阵中的一个数,它左边的数都比它小,下边的数都比它大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来缩小查找区间。
当前元素的查找区间为左下角的所有元素,例如元素 12 的查找区间如下:
<div align="center"> <img src="../pics//026d3cb4-67f7-4a83-884d-8032f57ec446.png" width="250"/> </div><br>
复杂度O(M + N) + O(1)
@ -261,25 +273,14 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
}
```
### 使用 Collections.reverse()
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> ret = new ArrayList<>();
while (listNode != null) {
ret.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(ret);
return ret;
}
```
### 使用头插法
利用链表头插法为逆序的特点。
头结点和第一个节点的区别:头结点是在头插法中使用的一个额外节点,这个节点不存储值;第一个节点就是链表的第一个真正存储值的节点。
头结点和第一个节点的区别:
- 头结点是在头插法中使用的一个额外节点,这个节点不存储值;
- 第一个节点就是链表的第一个真正存储值的节点。
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
@ -302,6 +303,20 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
}
```
### 使用 Collections.reverse()
```java
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ArrayList<Integer> ret = new ArrayList<>();
while (listNode != null) {
ret.add(listNode.val);
listNode = listNode.next;
}
Collections.reverse(ret);
return ret;
}
```
# 7. 重建二叉树
[NowCoder](https://www.nowcoder.com/practice/8a19cbe657394eeaac2f6ea9b0f6fcf6?tpId=13&tqId=11157&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking)
@ -322,22 +337,23 @@ inorder = [9,3,15,20,7]
前序遍历的第一个值为根节点的值,使用这个值将中序遍历结果分成两部分,左部分为树的左子树中序遍历结果,右部分为树的右子树中序遍历的结果。
```java
private Map<Integer, Integer> inOrderNumsIndexs = new HashMap<>(); // 缓存中序遍历数组的每个值对应的索引
// 缓存中序遍历数组的每个值对应的索引
private Map<Integer, Integer> inOrderNumsIndexs = new HashMap<>();
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
for (int i = 0; i < in.length; i++)
inOrderNumsIndexs.put(in[i], i);
return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
return reConstructBinaryTree(pre, 0, pre.length - 1, 0, in.length - 1);
}
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in, int inL, int inR) {
private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int inL, int inR) {
if (preL > preR)
return null;
TreeNode root = new TreeNode(pre[preL]);
int inIndex = inOrderNumsIndexs.get(root.val);
int leftTreeSize = inIndex - inL;
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, in, inL, inL + leftTreeSize - 1);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, in, inL + leftTreeSize + 1, inR);
root.left = reConstructBinaryTree(pre, preL + 1, preL + leftTreeSize, inL, inL + leftTreeSize - 1);
root.right = reConstructBinaryTree(pre, preL + leftTreeSize + 1, preR, inL + leftTreeSize + 1, inR);
return root;
}
```
@ -350,16 +366,6 @@ private TreeNode reConstructBinaryTree(int[] pre, int preL, int preR, int[] in,
给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。
## 解题思路
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
<div align="center"> <img src="../pics//cb0ed469-27ab-471b-a830-648b279103c8.png" width="250"/> </div><br>
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
<div align="center"> <img src="../pics//e143f6da-d114-4ba4-8712-f65299047fa2.png" width="250"/> </div><br>
```java
public class TreeLinkNode {
int val;
@ -373,6 +379,16 @@ public class TreeLinkNode {
}
```
## 解题思路
① 如果一个节点的右子树不为空,那么该节点的下一个节点是右子树的最左节点;
<div align="center"> <img src="../pics//cb0ed469-27ab-471b-a830-648b279103c8.png" width="250"/> </div><br>
② 否则,向上找第一个左链接指向的树包含该节点的祖先节点。
<div align="center"> <img src="../pics//e143f6da-d114-4ba4-8712-f65299047fa2.png" width="250"/> </div><br>
```java
public TreeLinkNode GetNext(TreeLinkNode pNode) {
if (pNode.right != null) {
@ -398,7 +414,7 @@ public TreeLinkNode GetNext(TreeLinkNode pNode) {
## 题目描述
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。队列中的元素为 int 类型。
用两个栈来实现一个队列,完成队列的 Push 和 Pop 操作。
## 解题思路
@ -442,7 +458,7 @@ public int pop() throws Exception {
<div align="center"> <img src="../pics//a0df8edc-581b-4977-95c2-d7025795b899.png" width="300"/> </div><br>
递归方法是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,避免重复求解子问题。
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
```java
public int Fibonacci(int n) {
@ -521,11 +537,11 @@ public int JumpFloor(int n) {
```java
public int JumpFloor(int n) {
if (n <= 1)
if (n <= 2)
return n;
int pre2 = 0, pre1 = 1;
int result = 0;
for (int i = 1; i <= n; i++) {
int pre2 = 1, pre1 = 2;
int result = 1;
for (int i = 2; i < n; i++) {
result = pre2 + pre1;
pre2 = pre1;
pre1 = result;