auto commit
This commit is contained in:
parent
0967a9ab23
commit
a2cf6fc9f9
|
@ -1,5 +1,6 @@
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
* [第二章 面试需要的基础知识](#第二章-面试需要的基础知识)
|
* [前言](#前言)
|
||||||
|
* [面试需要的基础知识](#面试需要的基础知识)
|
||||||
* [2. 实现 Singleton](#2-实现-singleton)
|
* [2. 实现 Singleton](#2-实现-singleton)
|
||||||
* [3. 数组中重复的数字](#3-数组中重复的数字)
|
* [3. 数组中重复的数字](#3-数组中重复的数字)
|
||||||
* [4. 二维数组中的查找](#4-二维数组中的查找)
|
* [4. 二维数组中的查找](#4-二维数组中的查找)
|
||||||
|
@ -17,7 +18,7 @@
|
||||||
* [13. 机器人的运动范围](#13-机器人的运动范围)
|
* [13. 机器人的运动范围](#13-机器人的运动范围)
|
||||||
* [14. 剪绳子](#14-剪绳子)
|
* [14. 剪绳子](#14-剪绳子)
|
||||||
* [15. 二进制中 1 的个数](#15-二进制中-1-的个数)
|
* [15. 二进制中 1 的个数](#15-二进制中-1-的个数)
|
||||||
* [第三章 高质量的代码](#第三章-高质量的代码)
|
* [高质量的代码](#高质量的代码)
|
||||||
* [16. 数值的整数次方](#16-数值的整数次方)
|
* [16. 数值的整数次方](#16-数值的整数次方)
|
||||||
* [17. 打印从 1 到最大的 n 位数](#17-打印从-1-到最大的-n-位数)
|
* [17. 打印从 1 到最大的 n 位数](#17-打印从-1-到最大的-n-位数)
|
||||||
* [18.1 在 O(1) 时间内删除链表节点](#181-在-o1-时间内删除链表节点)
|
* [18.1 在 O(1) 时间内删除链表节点](#181-在-o1-时间内删除链表节点)
|
||||||
|
@ -30,7 +31,7 @@
|
||||||
* [24. 反转链表](#24-反转链表)
|
* [24. 反转链表](#24-反转链表)
|
||||||
* [25. 合并两个排序的链表](#25-合并两个排序的链表)
|
* [25. 合并两个排序的链表](#25-合并两个排序的链表)
|
||||||
* [26. 树的子结构](#26-树的子结构)
|
* [26. 树的子结构](#26-树的子结构)
|
||||||
* [第四章 解决面试题的思路](#第四章-解决面试题的思路)
|
* [解决面试题的思路](#解决面试题的思路)
|
||||||
* [27. 二叉树的镜像](#27-二叉树的镜像)
|
* [27. 二叉树的镜像](#27-二叉树的镜像)
|
||||||
* [28.1 对称的二叉树](#281-对称的二叉树)
|
* [28.1 对称的二叉树](#281-对称的二叉树)
|
||||||
* [28.2 平衡二叉树](#282-平衡二叉树)
|
* [28.2 平衡二叉树](#282-平衡二叉树)
|
||||||
|
@ -46,7 +47,7 @@
|
||||||
* [36. 二叉搜索树与双向链表](#36-二叉搜索树与双向链表)
|
* [36. 二叉搜索树与双向链表](#36-二叉搜索树与双向链表)
|
||||||
* [37. 序列化二叉树](#37-序列化二叉树)
|
* [37. 序列化二叉树](#37-序列化二叉树)
|
||||||
* [38. 字符串的排列](#38-字符串的排列)
|
* [38. 字符串的排列](#38-字符串的排列)
|
||||||
* [第五章 优化时间和空间效率](#第五章-优化时间和空间效率)
|
* [优化时间和空间效率](#优化时间和空间效率)
|
||||||
* [39. 数组中出现次数超过一半的数字](#39-数组中出现次数超过一半的数字)
|
* [39. 数组中出现次数超过一半的数字](#39-数组中出现次数超过一半的数字)
|
||||||
* [40. 最小的 K 个数](#40-最小的-k-个数)
|
* [40. 最小的 K 个数](#40-最小的-k-个数)
|
||||||
* [41.1 数据流中的中位数](#411-数据流中的中位数)
|
* [41.1 数据流中的中位数](#411-数据流中的中位数)
|
||||||
|
@ -62,7 +63,7 @@
|
||||||
* [50. 第一个只出现一次的字符位置](#50-第一个只出现一次的字符位置)
|
* [50. 第一个只出现一次的字符位置](#50-第一个只出现一次的字符位置)
|
||||||
* [51. 数组中的逆序对](#51-数组中的逆序对)
|
* [51. 数组中的逆序对](#51-数组中的逆序对)
|
||||||
* [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点)
|
* [52. 两个链表的第一个公共结点](#52-两个链表的第一个公共结点)
|
||||||
* [第六章 面试中的各项能力](#第六章-面试中的各项能力)
|
* [面试中的各项能力](#面试中的各项能力)
|
||||||
* [53 数字在排序数组中出现的次数](#53-数字在排序数组中出现的次数)
|
* [53 数字在排序数组中出现的次数](#53-数字在排序数组中出现的次数)
|
||||||
* [54. 二叉搜索树的第 k 个结点](#54-二叉搜索树的第-k-个结点)
|
* [54. 二叉搜索树的第 k 个结点](#54-二叉搜索树的第-k-个结点)
|
||||||
* [55 二叉树的深度](#55-二叉树的深度)
|
* [55 二叉树的深度](#55-二叉树的深度)
|
||||||
|
@ -79,13 +80,29 @@
|
||||||
* [64. 求 1+2+3+...+n](#64-求-1+2+3++n)
|
* [64. 求 1+2+3+...+n](#64-求-1+2+3++n)
|
||||||
* [65. 不用加减乘除做加法](#65-不用加减乘除做加法)
|
* [65. 不用加减乘除做加法](#65-不用加减乘除做加法)
|
||||||
* [66. 构建乘积数组](#66-构建乘积数组)
|
* [66. 构建乘积数组](#66-构建乘积数组)
|
||||||
* [第七章 两个面试案例](#第七章-两个面试案例)
|
* [两个面试案例](#两个面试案例)
|
||||||
* [67. 把字符串转换成整数](#67-把字符串转换成整数)
|
* [67. 把字符串转换成整数](#67-把字符串转换成整数)
|
||||||
* [68. 树中两个节点的最低公共祖先](#68-树中两个节点的最低公共祖先)
|
* [68. 树中两个节点的最低公共祖先](#68-树中两个节点的最低公共祖先)
|
||||||
<!-- GFM-TOC -->
|
<!-- GFM-TOC -->
|
||||||
|
|
||||||
|
|
||||||
# 第二章 面试需要的基础知识
|
# 前言
|
||||||
|
|
||||||
|
**变量命名规范**
|
||||||
|
|
||||||
|
- nums 表示数组,matrix 表示矩阵;
|
||||||
|
- n 表示数组长度、字符串长度、树节点个数,以及其它具有一维性质的数据结构的元素个数;
|
||||||
|
- m, n 表示矩阵的行数和列数;
|
||||||
|
- first, last 表示闭区间:[first, last];
|
||||||
|
- begin, end 表示左闭右开区间:[begin, end);
|
||||||
|
- l, h 表示二分查找的闭区间:[l, h];
|
||||||
|
- ret 表示和结果相关的变量;
|
||||||
|
|
||||||
|
**复杂度简写说明**
|
||||||
|
|
||||||
|
O(nlog<sub>n</sub>) + O(n<sup>2</sup>),第一个指时间复杂度,第二个指空间复杂度。
|
||||||
|
|
||||||
|
# 面试需要的基础知识
|
||||||
|
|
||||||
## 2. 实现 Singleton
|
## 2. 实现 Singleton
|
||||||
|
|
||||||
|
@ -114,6 +131,8 @@ position-2 : (0,1,1,3,2,5) // nums[i] == nums[nums[i]], exit
|
||||||
|
|
||||||
遍历到位置 2 时,该位置上的数为 1,但是第 1 个位置上已经有一个 1 的值了,因此可以知道 1 重复。
|
遍历到位置 2 时,该位置上的数为 1,但是第 1 个位置上已经有一个 1 的值了,因此可以知道 1 重复。
|
||||||
|
|
||||||
|
复杂度:O(n) + O(1)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public boolean duplicate(int[] nums, int length, int[] duplication) {
|
public boolean duplicate(int[] nums, int length, int[] duplication) {
|
||||||
if (nums == null || length <= 0) return false;
|
if (nums == null || length <= 0) return false;
|
||||||
|
@ -141,26 +160,34 @@ private void swap(int[] nums, int i, int j) {
|
||||||
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
|
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
Consider the following matrix:
|
||||||
[
|
[
|
||||||
[ 1, 5, 9],
|
[1, 4, 7, 11, 15],
|
||||||
[10, 11, 13],
|
[2, 5, 8, 12, 19],
|
||||||
[12, 13, 15]
|
[3, 6, 9, 16, 22],
|
||||||
|
[10, 13, 14, 17, 24],
|
||||||
|
[18, 21, 23, 26, 30]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Given target = 5, return true.
|
||||||
|
Given target = 20, return false.
|
||||||
```
|
```
|
||||||
|
|
||||||
**解题思路**
|
**解题思路**
|
||||||
|
|
||||||
从右上角开始查找。因为矩阵中的一个数,它左边的数都比它来的小,下边的数都比它来的大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来改变行和列的下标,从而缩小查找区间。
|
从右上角开始查找。因为矩阵中的一个数,它左边的数都比它来的小,下边的数都比它来的大。因此,从右上角开始查找,就可以根据 target 和当前元素的大小关系来改变行和列的下标,从而缩小查找区间。
|
||||||
|
|
||||||
|
复杂度:O(m + n) + O(1)
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public boolean Find(int target, int [][] array) {
|
public boolean Find(int target, int[][] matrix) {
|
||||||
if (array == null || array.length == 0 || array[0].length == 0) return false;
|
if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false;
|
||||||
int m = array.length, n = array[0].length;
|
int m = matrix.length, n = matrix[0].length;
|
||||||
int row = 0, col = n - 1;
|
int r = 0, c = n - 1; // 从右上角开始
|
||||||
while (row < m && col >= 0) {
|
while (r <= m - 1 && c >= 0) {
|
||||||
if (target == array[row][col]) return true;
|
if (target == matrix[r][c]) return true;
|
||||||
else if (target < array[row][col]) col--;
|
else if (target > matrix[r][c]) r++;
|
||||||
else row++;
|
else c--;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -172,33 +199,37 @@ public boolean Find(int target, int [][] array) {
|
||||||
|
|
||||||
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为 We Are Happy. 则经过替换之后的字符串为 We%20Are%20Happy。
|
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为 We Are Happy. 则经过替换之后的字符串为 We%20Are%20Happy。
|
||||||
|
|
||||||
**题目要求**
|
|
||||||
|
|
||||||
以 O(1) 的空间复杂度和 O(n) 的时间复杂度来求解。
|
|
||||||
|
|
||||||
**解题思路**
|
**解题思路**
|
||||||
|
|
||||||
从后向前改变字符串。
|
现在字符串尾部填充任意字符,使得字符串的长度等于将字符串替换之后的长度。因为一个空格要替换成三个字符(%20),因此当遍历到一个空格时,需要在尾部填充两个任意字符。
|
||||||
|
|
||||||
|
令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。P1 从后向前遍历,当遍历到一个空格时,就需要令 P2 指向的位置填充 02%(注意是逆序的),否则就填充上 P1 指向字符的值。
|
||||||
|
|
||||||
|
从后向前遍历时为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。
|
||||||
|
|
||||||
|
复杂度:O(n) + O(1)
|
||||||
|
|
||||||
|
<div align="center"> <img src="../pics//35b0caf8-6f34-49db-93ed-d505e9eb3d99.png"/> </div><br>
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public String replaceSpace(StringBuffer str) {
|
public String replaceSpace(StringBuffer str) {
|
||||||
int n = str.length();
|
int oldLen = str.length();
|
||||||
for (int i = 0; i < n; i++) {
|
for (int i = 0; i < oldLen; i++) {
|
||||||
if (str.charAt(i) == ' ') {
|
if (str.charAt(i) == ' ') {
|
||||||
str.append(" "); // 尾部填充两个
|
str.append(" ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int idxOfOriginal = n - 1;
|
int idxOfOld = oldLen - 1;
|
||||||
int idxOfNew = str.length() - 1;
|
int idxOfNew = str.length() - 1;
|
||||||
while (idxOfOriginal >= 0 && idxOfNew > idxOfOriginal) {
|
while (idxOfOld >= 0 && idxOfNew > idxOfOld) {
|
||||||
if (str.charAt(idxOfOriginal) == ' ') {
|
char c = str.charAt(idxOfOld--);
|
||||||
|
if (c == ' ') {
|
||||||
str.setCharAt(idxOfNew--, '0');
|
str.setCharAt(idxOfNew--, '0');
|
||||||
str.setCharAt(idxOfNew--, '2');
|
str.setCharAt(idxOfNew--, '2');
|
||||||
str.setCharAt(idxOfNew--, '%');
|
str.setCharAt(idxOfNew--, '%');
|
||||||
} else {
|
} else {
|
||||||
str.setCharAt(idxOfNew--, str.charAt(idxOfOriginal));
|
str.setCharAt(idxOfNew--, c);
|
||||||
}
|
}
|
||||||
idxOfOriginal--;
|
|
||||||
}
|
}
|
||||||
return str.toString();
|
return str.toString();
|
||||||
}
|
}
|
||||||
|
@ -262,14 +293,15 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
ListNode head = new ListNode(-1); // 头结点
|
// 头插法构建逆序链表
|
||||||
ListNode cur = listNode;
|
ListNode head = new ListNode(-1);
|
||||||
while (cur != null) {
|
while (listNode != null) {
|
||||||
ListNode next = cur.next;
|
ListNode memo = listNode.next;
|
||||||
cur.next = head.next;
|
listNode.next = head.next;
|
||||||
head.next = cur;
|
head.next = listNode;
|
||||||
cur = next;
|
listNode = memo;
|
||||||
}
|
}
|
||||||
|
// 构建 ArrayList
|
||||||
ArrayList<Integer> ret = new ArrayList<>();
|
ArrayList<Integer> ret = new ArrayList<>();
|
||||||
head = head.next;
|
head = head.next;
|
||||||
while (head != null) {
|
while (head != null) {
|
||||||
|
@ -286,6 +318,25 @@ public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
|
||||||
|
|
||||||
根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。
|
根据二叉树的前序遍历和中序遍历的结果,重建出该二叉树。
|
||||||
|
|
||||||
|
```html
|
||||||
|
For example, given
|
||||||
|
|
||||||
|
preorder = [3,9,20,15,7]
|
||||||
|
inorder = [9,3,15,20,7]
|
||||||
|
|
||||||
|
Return the following binary tree:
|
||||||
|
|
||||||
|
3
|
||||||
|
/ \
|
||||||
|
9 20
|
||||||
|
/ \
|
||||||
|
15 7
|
||||||
|
```
|
||||||
|
|
||||||
|
**解题思路**
|
||||||
|
|
||||||
|
中序遍历的第一个值为树根节点的值,使用这个值将前序遍历结果分成两部分,左部分为树的左子树前序遍历结果,右部分为树的右子树前序遍历的结果。
|
||||||
|
|
||||||
```java
|
```java
|
||||||
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
|
public TreeNode reConstructBinaryTree(int[] pre, int[] in) {
|
||||||
return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
|
return reConstructBinaryTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
|
||||||
|
@ -614,7 +665,7 @@ public int NumberOf1(int n) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 第三章 高质量的代码
|
# 高质量的代码
|
||||||
|
|
||||||
## 16. 数值的整数次方
|
## 16. 数值的整数次方
|
||||||
|
|
||||||
|
@ -958,7 +1009,7 @@ private boolean isSubtree(TreeNode root1, TreeNode root2) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 第四章 解决面试题的思路
|
# 解决面试题的思路
|
||||||
|
|
||||||
## 27. 二叉树的镜像
|
## 27. 二叉树的镜像
|
||||||
|
|
||||||
|
@ -1419,7 +1470,7 @@ private void backtracking(char[] chars, boolean[] hasUsed, StringBuffer s) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 第五章 优化时间和空间效率
|
# 优化时间和空间效率
|
||||||
|
|
||||||
## 39. 数组中出现次数超过一半的数字
|
## 39. 数组中出现次数超过一半的数字
|
||||||
|
|
||||||
|
@ -1900,7 +1951,7 @@ public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 第六章 面试中的各项能力
|
# 面试中的各项能力
|
||||||
|
|
||||||
## 53 数字在排序数组中出现的次数
|
## 53 数字在排序数组中出现的次数
|
||||||
|
|
||||||
|
@ -2323,7 +2374,7 @@ public int[] multiply(int[] A) {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
# 第七章 两个面试案例
|
# 两个面试案例
|
||||||
|
|
||||||
## 67. 把字符串转换成整数
|
## 67. 把字符串转换成整数
|
||||||
|
|
||||||
|
|
BIN
pics/35b0caf8-6f34-49db-93ed-d505e9eb3d99.png
Normal file
BIN
pics/35b0caf8-6f34-49db-93ed-d505e9eb3d99.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 32 KiB |
Loading…
Reference in New Issue
Block a user