目录
- 79. Word Search
- 48. Rotate Image
- 23. Merge k Sorted Lists
- 56 Merge Intervals
- 72 Edit Distance
- 78 Subsets
- 102. Binary Tree Level Order Traversal
- 105. Construct Binary Tree from Preorder and Inorder Traversal
- 406. Queue Reconstruction by Height
- 437. Path Sum III
- 103. Binary Tree Zigzag Level Order Traversal
- 1269. Number of Ways to Stay in the Same Place After Some Steps
- 912. Sort an Array
- 189. Rotate Array
- 145. Binary Tree Postorder Traversal
- 142. Linked List Cycle II
79. Word Search
掌握C语言中二维指针的定义(不定长度二维数组传参需要使用):
int** visited = malloc(sizeof(int*) * boardSize);
for (int i = 0; i < boardSize; i++) {
visited[i] = malloc(sizeof(int) * boardColSize[0]);
memset(visited[i], 0, sizeof(int) * boardColSize[0]);
}
48. Rotate Image
四个变量a, b, c, d, a赋值给b,b给c,c给d,d给a,只需要一个临时变量。
23. Merge k Sorted Lists
Java中优先队列的用法(本质是堆排序,每次维护堆消耗logn时间):
class Status implements Comparable<Status> {
int val;
ListNode ptr;
Status(int val, ListNode ptr) { //Status这个对象自己定义,本题中为链表结点
this.val = val;
this.ptr = ptr;
}
public int compareTo(Status status2) {
return this.val - status2.val;
}
}
PriorityQueue<Status> queue = new PriorityQueue<Status>(); //初始化
queue.offer(new Status(node.val, node)); //入队
Status f = queue.poll(); //出队 注意这里的f就是队里的结点(没有new),本题是就地建堆
定义和初始化更简洁的写法:
Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val); //优先队列元素即为链表结点,比较条件使用lambda表达式
56 Merge Intervals
Java中可实现堆栈的双端队列用法:
Deque deque = new LinkedList();
队列操作:addLast(e),removeFirst(),peekFirst()
栈操作:addFirst(e),removeFirst(),peekFirst()
72 Edit Distance
二维动态规划基本操作:
- 定义长宽分别为m+1、n+1的二维数组;
- 第0行与第0列分别初始化;
- 1-m, 2-n 填表
78 Subsets
dfs循环时一定不要忘记恢复初始状态。如果考虑是否跳过当前元素,可以不使用循环,更简单。
102. Binary Tree Level Order Traversal
广度优先搜索时,为了判断当前在第几层,可每层使用一次for循环,循环次数为开始时队列的长度,即当前层的节点数。
注意:循环条件不能是从0到队列长为止,因为队列长度在变化。可以用一个变量记录下当前队列长,或者从队列长递减到0。
105. Construct Binary Tree from Preorder and Inorder Traversal
Java中哈希的使用:
private Map<Integer, Integer> indexMap;
indexMap = new HashMap<Integer, Integer>();
indexMap.put(key, value);
int value= indexMap.get(key);
int value= indexMap.getOrDefault(key, -1);
406. Queue Reconstruction by Height
数组排序重写:
Arrays.sort(people, new Comparator<int[]>() { //多态指明类型,否则需要在compare()中强制类型转换
public int compare(int[] person1, int[] person2) {
if (person1[0] != person2[0]) {
return person2[0] - person1[0]; //降序
} else {
return person1[1] - person2[1]; //升序
}
}
});
1482. Minimum Number of Days to Make m Bouquets补充:如何对int数组排序?
直接使用Arrays.sort(a,Collections.reverseOrder());
;
自己重写Comparator,数组必须为Integer对象数组才行!
补充:其实这也得是对象数组。int降序要么转为integer,要么升序再颠倒
Java ArrayList toArray() 方法的语法为:
arraylist.toArray(T[] arr)
T [] arr(可选参数)- 用于存储数组元素的数组
如果参数 T[] arr 作为参数传入到方法,则返回 T 类型的数组(否则Object型)
349. Intersection of Two Arrays补充:Integer类型的ArrayList不能使用toArray()转成int [],只能循环。
可以先声明一个长数组,再使用Arrays.copyOfRange(T[ ] original,int from,int to);
实现数组复制去除多余的零元素。
437. Path Sum III
List元素修改函数为:arraylist.set(int index, E element)
。
无论是使用for迭代还是get()得到的元素都不能直接赋值修改。
103. Binary Tree Zigzag Level Order Traversal
假设有以下代码:
List<Integer> slist=new ArrayList();
slist.add(1);
List<List<Integer>> list=new ArrayList();
list.add(slist);
slist=new ArrayList();
那么问题来了,list中第一个元素是空列表还是包含“1”的列表?
实际上是包含“1”的列表,因为Java的集合类的元素是对象引用,但注意slist本身也只是引用,真正在list.add(slist)
添加的引用是第一行的new ArrayList():
参考Java中list存放的是值还是对象的引用问题
1269. Number of Ways to Stay in the Same Place After Some Steps
动态规划,两个数组交替运行下面的语句:
nw[j]=od[j]+od[j-1]+od[j+1];
题目中温馨提示:
Since the answer may be too large, return it modulo 10^9 + 7.
如果不做任何处理,数组元素不断达到
2
31
−
1
2^{31}-1
231−1然后负溢出。处理也很简单,因为题目计算只有加法,所以在计算的时候不断模
1
0
9
+
7
10^{9}+7
109+7就可以了。
1
0
9
+
7
10^{9}+7
109+7是接近于int表示最大正数的一个大质数,这个数的两倍还在int表示范围内,三倍就会溢出。如果我们把该语句改成
nw[j]=(od[j]%m+od[j-1]%m+od[j+1]%m)%m; //m=1000000007
是否就可以了呢?答案是否定的。od[j]%m
这一步没有必要,因为我们计算时已经保证od数组都不会大于m;od[j]%m+od[j-1]%m+od[j+1]%m
这一步反而是有可能溢出的,如果这三个元素都比较接近m的话。由于两个m相加不会溢出,所以应该改成:
nw[j]=((od[j]+od[j-1])%m+od[j+1])%m;
912. Sort an Array
堆排序要点:
左子节点、右子节点分别为
int lson = (i << 1) + 1;
int rson = (i << 1) + 2;
循环条件是左子节点存在,循环内部取右子节点值时需要判断是否超范围;
要使结果为正序,需要建立大根堆,不断把根放最后;
调整堆参数要包括起止点。
189. Rotate Array
最大公约数求法:
public int gcd(int x, int y) {
return y > 0 ? gcd(y, x % y) : x;
}
145. Binary Tree Postorder Traversal
- 使用两个栈辅助。主栈不断弹出一个节点存入辅栈,再压入左右非空子节点,这样访问顺序为右子树→左子树→父节点,辅栈倒过来就对了:
public class Test{
Stack<TreeNode> stack1 = new Stack<TreeNode>();
Stack<TreeNode> stack2 = new Stack<TreeNode>();
public void postOrder(TreeNode root)
{
stack1.push(root);
while(!stack1.isEmpty())
{
TreeNode pop = stack1.pop();
stack2.push(pop);
if(pop.left!=null)
stack1.push(pop.left);
if(pop.right!=null)
stack1.push(pop.right);
}
while(!stack2.isEmpty())
{
System.out.println(stack2.pop().val+" ");
}
}
- 使用一个集合存储第一次回溯遇到的父节点(或使用标志位):
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> ans = new ArrayList<>();
Stack<TreeNode> s = new Stack<>();
Set<TreeNode> seen = new HashSet<>();
while (root != null || !s.isEmpty()) {
if (root == null && seen.contains(s.peek())) {
ans.add(s.pop().val);
} else if (root == null) {
seen.add(s.peek());
root = s.peek().right;
} else {
s.push(root);
root = root.left;
}
}
return ans;
}
}
- 只需要一个栈和一个辅助节点prev,不断向左遍历压栈,到头不断向右遍历压栈,到头记录并更新prev,从而根据
root.right == prev
判是否为第二次回到root:
class Solution {
public List<Integer> postorderTraversal(TreeNode root) {
List<Integer> res = new ArrayList<Integer>();
if (root == null) {
return res;
}
Deque<TreeNode> stack = new LinkedList<TreeNode>();
TreeNode prev = null;
while (root != null || !stack.isEmpty()) {
while (root != null) {
stack.push(root);
root = root.left;
}
root = stack.pop();
if (root.right == null || root.right == prev) {
res.add(root.val);
prev = root;
root = null; //Attention!
} else {
stack.push(root);
root = root.right;
}
}
return res;
}
}
142. Linked List Cycle II
关键在于 2 ( a + b ) = a + b + n ( b + c ) ⟹ a = c + ( n − 1 ) ( b + c ) 2(a+b)=a+b+n(b+c)⟹a=c+(n−1)(b+c) 2(a+b)=a+b+n(b+c)⟹a=c+(n−1)(b+c),这里把a放到等式一端,就能看出来所求的头节点到入环点的距离与相遇点到入环点的距离差了整环长的倍数。