Leetcode 相关知识点 day5
#####用于作者每日有需所作笔记
1.岛屿问题
**二叉树DFS 的基本结构**
void traverse(TreeNode root) {
// 判断 base case
if (root == null) {
return;
}
// 访问两个相邻结点:左子结点、右子结点
traverse(root.left);
traverse(root.right);
}
**表格DFS 的基本结构**
void dfs(int[][] grid, int r, int c) {
// 判断 base case
// 如果坐标 (r, c) 超出了网格范围,直接返回
if (!inArea(grid, r, c)) {
return;
}
// 访问上、下、左、右四个相邻结点
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
}
// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
return 0 <= r && r < grid.length
&& 0 <= c && c < grid[0].length;
}
网格结构的 DFS 与二叉树的 DFS 最大的不同之处在于:
遍历中可能遇到遍历过的结点。这是因为,网格结构本质上是一个「图」,
我们可以把每个格子看成图中的结点,每个结点有向上下左右的四条边。
在图中遍历时,自然可能遇到重复遍历结点。
***我们在框架代码中加入避免重复遍历的语句:***
void dfs(int[][] grid, int r, int c) {
// 判断 base case
if (!inArea(grid, r, c)) {
return;
}
// 如果这个格子不是岛屿,直接返回
if (grid[r][c] != 1) {
return;
}
grid[r][c] = 2; // 将格子标记为「已遍历过」
// 访问上、下、左、右四个相邻结点
dfs(grid, r - 1, c);
dfs(grid, r + 1, c);
dfs(grid, r, c - 1);
dfs(grid, r, c + 1);
}
// 判断坐标 (r, c) 是否在网格中
boolean inArea(int[][] grid, int r, int c) {
return 0 <= r && r < grid.length
&& 0 <= c && c < grid[0].length;
}
2.二维数组根据第一列排序
Arrays.sort(prerequisites,new Comparator<int[]>() {
public int compare(int[] o1, int[] o2) {
return o1[0]-o2[0];
}
});
如果第一列相同,就根据第二列排序
Arrays.sort(ts_id,new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
if (o1[0] == o2[0]) {
return o1[1] - o2[1];
}
return o1[0]-o2[0];
}
});
3.常用小技巧总结
*****************************************************
利用按位异或的性质,可以得到
mid 是偶数时,mid + 1 = mid ⊕ 1
mid 是奇数时,mid − 1 = mid ⊕ 1
*****************************************************
三指针求和时,往往对于有序数组,只需遍历第一个指针,第二第三指针同时从首尾同步进行。
当总值较大不满足时,左移第三个指针,在决定是否右移第二个指针。
*****************************************************
往往无序的数组,进行子数组操作时,不能使用滑动窗口。
滑动窗口多用于操作有序或有规律的数组。
无序的数组常用动态规划和双指针算法。
*****************************************************
自然二进制码 ^ 自然二进制码右移一位,即G = B ^ (B >> 1)
*****************************************************
当给定链表需要从中间截断时,即归并排序。需注意寻找中间节点时易造成栈溢出。
ListNode slow = head;
ListNode fast = head.next; //若改成fast = head; ---> 栈溢出
while(fast != null && fast.next != null){
slow = slow.next;
fast = fast.next.next;
}
*****************************************************
前缀树的初始化
class Trie {
private Trie[] children;
private boolean isEnd;
public Trie() {
children = new Trie[26];
isEnd = false;
}
public void insert(String word) {
Trie node = this;
......
}
*****************************************************
**完全二叉树**:
将完全二叉树按序放入数组中,若数组长度为heasize,
最后一个节点的位置为heapsize-1,该节点的父节点的位置为heapsize-1-1/2。
//left和right表示当前父节点i的两个左右子节点。
int left = i * 2 + 1, right = i * 2 + 2, largest = i;
*****************************************************
统计1到n每个数的二进制含1个数。
用动态规划求,传递函数为:
dp[i] = dp[i/2]; 若i为偶数;
dp[i] = dp[i-1]+1; 若i为奇数;
*****************************************************
求路径和往往用前缀和结合Map实现低时间复杂度。
值得注意的是:递归时需要状态还原。
*****************************************************
寻找数组中未出现的数字,将数组中的数字当做索引,进行操作。
后续遍历每个位置,不达要求的即数组中没出现过得数字。
*****************************************************
一次遍历,双指针同时左右两边向中间移动。
for(int i = 0; i < nums.length; i++){
left = i;
right = nums.length-i-1;
}
*****************************************************
4.水容量问题
水容量:容量大小取决于短板高度。 双指针从左右两段开始往内缩进,每次让短板缩进。如下图: