剑指 Offer 03. 数组中重复的数字
关键词:Set
、重复
问题:从一维数组中找出一个重复数
解决方法:
使用Set存储,add方法,当集合已有元素时返回false,表明重复了。
剑指 Offer 04. 二维数组中的查找
关键词:数组递增
问题:从左上角向右向下递增的二维数组,查找某个值。
解决方法:
从右上角开始
- 当前值等于目标,返回true
- 当前值大于目标,向左移动一列
- 当前值小于目标,向下移动一行
剑指 Offer 05. 替换空格
关键词:StringBuffer
问题:将字符串s中的空格替换为某个串
解决方法:
使用StringBuffer sb = new StringBuffer();
char[] arr = s.toCharArray();
sb.append(arr[i]);
当arr[i]为空格时,sb.append(“xx串”);
剑指 Offer 06. 从尾到头打印链表
关键词:链表倒序
问题:给你链表头部,从尾到头打印链表
解决方法:
- 正序遍历链表,用栈保存。栈弹出的顺序即为答案。
- 使用递归方法,在递过去的时候不管,归回来时,将链表节点的值加入list中,即为答案。
关键api:
new Arraylist<>();
new LinkedList<>();
剑指 Offer 07. 重建二叉树
关键词:重建二叉树
、前序遍历
、中序遍历
问题:给你二叉树的不含空节点的前序遍历和中序遍历结果,让你重建出二叉树
解决方法:
递归函数
TreeNode dfs(int left, int right) {
preorder_index++;
//map 是 inorder[i] -> i
Integer pos = map.get(preorder[preorder_index]);
if(pos!=null){
TreeNode res = new TreeNode(preorder[preorder_index]);
res.left = dfs(left, pos-1);
res.right = dfs(pos+1, right);
return res;
}
return null;
}
剑指 Offer 37. 序列化二叉树
关键词:前序遍历
、重建二叉树
问题:实现二叉树的序列化和反序列化算法
解决方法:
序列化:含空节点的前序遍历
反序列化:按前序遍历的样子建树
public String serialize(TreeNode root) {
StringBuilder builder = new StringBuilder();
serialize0(root, builder);
builder.deleteCharAt(builder.length()-1);
return builder.toString();
}
private void serialize0(TreeNode root, StringBuilder builder) {
if(!root)
builder.append("null,");
builder.append(root.val).append(",");
serialize0(root.left);
serialize0(root.right);
}
public TreeNode deserialize(String encode) {
String[] strs = encode.split(",");
return deserialize0(Arrays.asList(strs));
}
private TreeNode deserialize0(List<String> list){
if(list.get(0).equals("null")) {
list.remove(0);
return null;
}
TreeNode root = new TreeNode(list.get(0));
root.left = deserialize0(list);
root.right = deserialize0(list);
}
剑指 Offer 09. 用两个栈实现队列
关键词:两个栈
问题:用两个栈实现队列的offer和poll方法
解决方法:
使用两个栈offerStack、pollStack
offer方法将元素push进offerStack
poll方法
- 若pollStack为空,将offerStack栈混洗到pollStack
- 若pollStack不为空,直接pop。
关键api:
Deque stack = new LinkedList<>();
剑指 Offer 10- I. 斐波那契数列
关键词:斐波那契数列
问题:求斐波那契数列的第n项,答案需取模1000000007。
解决方法:
用迭代求。
int a = 0, b = 1, c = 0, t = 1000000007;
for(int i = 3;i<=n;i++){
c = (a + b)%t;
a = b;
b = c;
}
剑指 Offer 10- II. 青蛙跳台阶问题
关键词:斐波那契数列
问题:青蛙一次可跳1或2级台阶,求跳到n级台阶有多少种跳法。
解决方法:递推式和斐波那契数列的一样,只是起始值是1、1。仿照斐波那契数列的解法即可。
剑指 Offer 11. 旋转数组的最小数字
关键词:旋转数组
、二分查找变形
问题:对存在重复值的升序数组旋转一次,求数组的最小值。旋转指将数组开始的元素搬到末尾,例如[1,2,3,4,5] -> [3,4,5,1,2]。
解决方法:
- 线性遍历数组
- 当arr[i]>arr[i+1]时,arr[i+1]为最小值
- 未出现arr[i]>arr[i+1]的情况,arr[0]为最小值
此方法时间效率为O(n)
- 二分查找O(log n)
public int binarySearchMinValue(int[] arr) {
int left = 0, right = arr.length-1;
while(left<=right){
int mid = left + (right - left)/2;
if(arr[mid]==arr[right])
right--;
else if(arr[mid]>arr[right])
left = mid + 1;
else
right = mid;
}
return left<arr.length?arr[left]:-1;
}
剑指 Offer 12. 矩阵中的路径
关键词:深度优先搜索
、矩阵搜索
问题:在二维字符数组中查找是否存在相邻的格子像线一般连接成单词word。
解决方法:
深度优先搜索
private char[] word;
private char[][] arr;
boolean dfs(int i, int j, int k) {
if(i<0||i>=arr.length||j<0||j>=arr[0].length || arr[i][j]!=word[k])
return false;
if(k==word.length-1)
return true;
arr[i][j] = '\0';
boolean res = dfs(i+1,j,k+1) || dfs(i-1,j,k) || dfs(i,j+1,k) || dfs(i,j-1,k);
arr[i][j] = word[k];
return res;
}
剑指 Offer 13. 机器人的运动范围
关键词:广度优先搜索
问题:从mxn矩阵的0x0位置能到达的最多格子数。横坐标x、纵坐标y,应该满足某个条件。
解决方法:
广度优先搜索
class MyClass {
int x;
int y;
public MyClass(int a, int b){
x = a;
y = b;
}
}
public int bfs(int m, int n) {
int count = 0;
int[][] offset = new int[][]{
{