全榜 TOP10
排名 题目 频次
滑动窗口的模板
//外层循环扩展右边界,内层循环扩展左边界
for (int l = 0, r = 0 ; r < n ; r++) {
//当前考虑的元素
while (l <= r && check()) {//区间[left,right]不符合题意
//扩展左边界
}
//区间[left,right]符合题意,统计相关信息
}题解
class Solution {
public int lengthOfLongestSubstring(String s) {
//滑动窗口
char[] ss = s.toCharArray();
Set<Character> set = new HashSet<>();//去重
int res = 0;//结果
for(int left = 0, right = 0; right < s.length(); right++) {//每一轮右端点都扩一个。
char ch = ss[right];//right指向的元素,也是当前要考虑的元素
while(set.contains(ch)) {//set中有ch,则缩短左边界,同时从set集合出元素
set.remove(ss[left]);
left++;
}
set.add(ss[right]);//别忘。将当前元素加入。
res = Math.max(res, right - left + 1);//计算当前不重复子串的长度。
}
return res;
}
}LinkedHashMap按照读取顺序排序
内部是靠 建立一个双向链表 来维护这个顺序的,在每次插入、删除后,都会调用一个函数来进行 双向链表的维护 ,准确的来说,是有三个函数来做这件事,这三个函数都统称为 回调函数 ,这三个函数分别是:
void afterNodeAccess(Node<K,V> p) { }
其作用就是在访问元素之后,将该元素放到双向链表的尾巴处(所以这个函数只有在按照读取的顺序的时候才会执行),之所以提这个,是建议大家去看看,如何优美的实现在双向链表中将指定元素放入链尾!
void afterNodeRemoval(Node<K,V> p) { }
其作用就是在删除元素之后,将元素从双向链表中删除,还是非常建议大家去看看这个函数的,很优美的方式在双向链表中删除节点!
void afterNodeInsertion(boolean evict) { }
这个才是我们题目中会用到的,在插入新元素之后,需要回调函数判断是否需要移除一直不用的某些元素!
继承 LinkedHashMap,然后复写 removeEldestEntry()函数,就能拥有我们自己的缓存策略!/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
// 人之初生,过去为空,现在从头,未来不存
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next;//未来出于现在
curr.next = prev;//现在指向过去
prev = curr;//过去成为现在
curr = next;//现在成为未来
}
return prev;//生之将亡,唯过去返回彼岸
}
}class Solution {
int quickselect(int[] nums, int l, int r, int k) {
if (l == r) return nums[k];
int x = nums[l], i = l - 1, j = r + 1;
while (i < j) {
do i++; while (nums[i] < x);
do j--; while (nums[j] > x);
if (i < j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
}
if (k <= j) return quickselect(nums, l, j, k);
else return quickselect(nums, j + 1, r, k);
}
public int findKthLargest(int[] _nums, int k) {
int n = _nums.length;
return quickselect(_nums, 0, n - 1, n - k);
}
}6 LeetCode 5 最长回文子串 33 次
7 LeetCode 200 岛屿数量 32 次
8 LeetCode 53 最大子数组和 30 次
9 LeetCode 88 合并两个有序数组 29 次
10 LeetCode 19 删除倒数第N个节点 27 次
滑动窗口 + 双指针
1 LeetCode 3 无重复字符最长子串 129 次
2 LeetCode 88 合并两个有序数组 29 次
3 LeetCode 15 三数之和 27 次
4 LeetCode 42 接雨水 25 次
5 LeetCode 209 长度最小的子数组 12 次
6 LeetCode 239 滑动窗口最大值 9 次
LC3 出现 129 次,是第二名的 4 倍以上,字节脸面题,必须 10 分钟内 bug-free 写完
接雨水(双指针 / 单调栈)两种解法都要会
动态规划
1 LeetCode 5 最长回文子串 33 次
2 LeetCode 53 最大子数组和 30 次
3 LeetCode 300 最长递增子序列 24 次
4 LeetCode 121 买卖股票的最佳时机 23 次
5 LeetCode 72 编辑距离(Hard) 20 次
6 LeetCode 322 零钱兑换 14 次
7 LeetCode 1143 最长公共子序列 12 次
8 LeetCode 122 买卖股票 II 12 次
9 LeetCode 198 打家劫舍 8 次
10 LeetCode 70 爬楼梯 7 次
子串 / 子序列类 DP(LC5 / 300 / 1143)是重点
编辑距离 Hard 题出了 20 次,字节面试官最爱
写完必被追问:能否把 O(mn) 优化到 O(n)?
链表
1 LeetCode 206 翻转链表 40 次
2 LeetCode 25 K 个一组翻转链表 38 次
3 LeetCode 19 删除倒数第 N 个节点 27 次
4 LeetCode 23 合并 K 个升序链表 20 次
5 LeetCode 21 合并两个有序链表 14 次
6 LeetCode 141 环形链表 14 次
7 LeetCode 148 排序链表 13 次
8 LeetCode 92 反转链表 II 12 次
9 LeetCode 2 两数相加 11 次
反转链表系列(206 / 25 / 92)三道合计 90 次,字节最爱考
难度从入门到 Hard 都有,建议从简到难刷
链表题数最多(9 道),必须全部熟练掌握
栈 / 队列 / 哈希 / 设计
1 LeetCode 146 LRU 缓存 55 次
2 LeetCode 20 有效的括号 27 次
3 LeetCode 1 两数之和 17 次
4 LeetCode 46 全排列 16 次
5 LeetCode 165 比较版本号 16 次
6 LeetCode 232 用栈实现队列 14 次
7 LeetCode 415 字符串相加 13 次
8 LeetCode 22 括号生成 7 次
LRU 缓存:38 次暴涨到 55 次,全榜第 2
面试官要求手写双向链表 + 哈希表,禁用 LinkedHashMap / OrderedDict
写完必被追问:并发场景下淘汰逻辑有没有问题?
二分查找 + 排序 / 数组
1 LeetCode 215 数组中的第K大元素 39 次
2 LeetCode 200 岛屿数量 32 次
3 LeetCode 56 合并区间 18 次
4 LeetCode 33 搜索旋转排序数组 15 次
5 LeetCode 34 排序数组中查找首尾位置 12 次
6 LeetCode 912 排序数组 11 次
7 LeetCode 4 寻找两个正序数组的中位数 10 次
8 LeetCode 75 颜色分类 8 次
二叉树 + BFS
1 LeetCode 102 二叉树的层序遍历 28 次
2 LeetCode 236 二叉树的最近公共祖先 25 次
3 LeetCode 104 二叉树的最大深度 22 次
4 LeetCode 94 二叉树的中序遍历 18 次
5 LeetCode 124 二叉树中的最大路径和 15 次
6 LeetCode 199 二叉树的右视图 12 次
7 LeetCode 226 翻转二叉树 10 次
评论区