大厂校招必刷60 题 Java / C++ / Go / Python解法
这份文档不是讲完整题解,而是把开发岗 60 题里最常用的代码模板按语言整理出来。
目标只有一个:面试时别在基础写法上浪费时间。
使用方式:
先熟悉你自己的主语言模板
再把同题型模板写到能脱稿
面试前只复习这些高频骨架
一、数组 / 哈希
1. 两数之和
Java
Map<Integer, Integer> map = new HashMap<>(); for (int i = 0; i < nums.length; i++) { int need = target - nums[i]; if (map.containsKey(need)) { return new int[]{map.get(need), i}; } map.put(nums[i], i); } return new int[0];C++
unordered_map<int, int> mp; for (int i = 0; i < nums.size(); i++) { int need = target - nums[i]; if (mp.count(need)) return {mp[need], i}; mp[nums[i]] = i; } return {};Go
mp := map[int]int{} for i, v := range nums { need := target - v if j, ok := mp[need]; ok { return []int{j, i} } mp[v] = i } return nilPython
mp = {} for i, v in enumerate(nums): need = target - v if need in mp: return [mp[need], i] mp[v] = i return []2. 前缀和模板
Java
int[] pre = new int[n + 1]; for (int i = 0; i < n; i++) { pre[i + 1] = pre[i] + nums[i]; } int sum = pre[r + 1] - pre[l];C++
vector<int> pre(n + 1, 0); for (int i = 0; i < n; i++) pre[i + 1] = pre[i] + nums[i]; int sum = pre[r + 1] - pre[l];Go
pre := make([]int, n+1) for i := 0; i < n; i++ { pre[i+1] = pre[i] + nums[i] } sum := pre[r+1] - pre[l]Python
pre = [0] * (n + 1) for i in range(n): pre[i + 1] = pre[i] + nums[i] sum_ = pre[r + 1] - pre[l]校招大礼包获取:入口
可能是至今最全,最好,最实用的校招大礼包,减少信息差,预期漫步无敌的刷提,不如有的放矢,针对性的准备,这样才能有效备考,有了这份资料,不说100%拿到offer,至少帮你提升50%概率拿到offer
二、双指针 / 滑动窗口
3. 无重复字符的最长子串模板
Java
Map<Character, Integer> map = new HashMap<>(); int left = 0, ans = 0; for (int right = 0; right < s.length(); right++) { char c = s.charAt(right); if (map.containsKey(c)) { left = Math.max(left, map.get(c) + 1); } map.put(c, right); ans = Math.max(ans, right - left + 1); } return ans;C++
unordered_map<char, int> mp; int left = 0, ans = 0; for (int right = 0; right < s.size(); right++) { char c = s[right]; if (mp.count(c)) left = max(left, mp[c] + 1); mp[c] = right; ans = max(ans, right - left + 1); } return ans;Go
mp := map[byte]int{} left, ans := 0, 0 for right := 0; right < len(s); right++ { c := s[right] if idx, ok := mp[c]; ok && idx >= left { left = idx + 1 } mp[c] = right if right-left+1 > ans { ans = right - left + 1 } } return ansPython
mp = {} left = ans = 0 for right, c in enumerate(s): if c in mp and mp[c] >= left: left = mp[c] + 1 mp[c] = right ans = max(ans, right - left + 1) return ans4. 滑动窗口最大值 单调队列模板
Java
Deque<Integer> deque = new ArrayDeque<>(); for (int i = 0; i < nums.length; i++) { while (!deque.isEmpty() && deque.peekFirst() <= i - k) deque.pollFirst(); while (!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]) deque.pollLast(); deque.offerLast(i); if (i >= k - 1) ans.add(nums[deque.peekFirst()]); }C++
deque<int> dq; for (int i = 0; i < nums.size(); i++) { while (!dq.empty() && dq.front() <= i - k) dq.pop_front(); while (!dq.empty() && nums[dq.back()] <= nums[i]) dq.pop_back(); dq.push_back(i); if (i >= k - 1) ans.push_back(nums[dq.front()]); }Go
dq := []int{} for i := 0; i < len(nums); i++ { if len(dq) > 0 && dq[0] <= i-k { dq = dq[1:] } for len(dq) > 0 && nums[dq[len(dq)-1]] <= nums[i] { dq = dq[:len(dq)-1] } dq = append(dq, i) if i >= k-1 { ans = append(ans, nums[dq[0]]) } }Python
from collections import deque dq = deque() for i, v in enumerate(nums): while dq and dq[0] <= i - k: dq.popleft() while dq and nums[dq[-1]] <= v: dq.pop() dq.append(i) if i >= k - 1: ans.append(nums[dq[0]])三、链表
5. 反转链表模板
Java
ListNode prev = null, cur = head; while (cur != null) { ListNode next = cur.next; cur.next = prev; prev = cur; cur = next; } return prev;C++
ListNode* prev = nullptr; ListNode* cur = head; while (cur) { ListNode* next = cur->next; cur->next = prev; prev = cur; cur = next; } return prev;Go
var prev *ListNode cur := head for cur != nil { next := cur.Next cur.Next = prev prev = cur cur = next } return prevPython
prev, cur = None, head while cur: nxt = cur.next cur.next = prev prev = cur cur = nxt return prev6. 快慢指针找环 / 中点模板
Java
ListNode slow = head, fast = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) return true; } return false;C++
ListNode *slow = head, *fast = head; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; if (slow == fast) return true; } return false;Go
slow, fast := head, head for fast != nil && fast.Next != nil { slow = slow.Next fast = fast.Next.Next if slow == fast { return true } } return falsePython
slow = fast = head while fast and fast.next: slow = slow.next fast = fast.next.next if slow == fast: return True return False四、栈 / 堆
7. 单调栈模板
Java
Deque<Integer> stack = new ArrayDeque<>(); for (int i = 0; i < n; i++) { while (!stack.isEmpty() && nums[stack.peek()] < nums[i]) { int idx = stack.pop(); } stack.push(i); }C++
stack<int> st; for (int i = 0; i < n; i++) { while (!st.empty() && nums[st.top()] < nums[i]) { int idx = st.top(); st.pop(); } st.push(i); }Go
st := []int{} for i := 0; i < n; i++ { for len(st) > 0 && nums[st[len(st)-1]] < nums[i] { idx := st[len(st)-1] _ = idx st = st[:len(st)-1] } st = append(st, i) }Python
st = [] for i, v in enumerate(nums): while st and nums[st[-1]] < v: idx = st.pop() st.append(i)8. Top K 小顶堆模板
Java
PriorityQueue<Integer> pq = new PriorityQueue<>(); for (int x : nums) { pq.offer(x); if (pq.size() > k) pq.poll(); } return pq.peek();C++
priority_queue<int, vector<int>, greater<int>> pq; for (int x : nums) { pq.push(x); if (pq.size() > k) pq.pop(); } return pq.top();Go
type MinHeap []int func (h MinHeap) Len() int { return len(h) } func (h MinHeap) Less(i, j int) bool { return h[i] < h[j] } func (h MinHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] } func (h *MinHeap) Push(x interface{}) { *h = append(*h, x.(int)) } func (h *MinHeap) Pop() interface{} { old := *h x := old[len(old)-1] *h = old[:len(old)-1] return x }Python
import heapq hp = [] for x in nums: heapq.heappush(hp, x) if len(hp) > k: heapq.heappop(hp) return hp[0]五、二分查找
9. 标准二分模板
Java
int left = 0, right = nums.length - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) return mid; if (nums[mid] < target) left = mid + 1; else right = mid - 1; } return -1;C++
int left = 0, right = nums.size() - 1; while (left <= right) { int mid = left + (right - left) / 2; if (nums[mid] == target) return mid; if (nums[mid] < target) left = mid + 1; else right = mid - 1; } return -1;Go
left, right := 0, len(nums)-1 for left <= right { mid := left + (right-left)/2 if nums[mid] == target { return mid } if nums[mid] < target { left = mid + 1 } else { right = mid - 1 } } return -1Python
left, right = 0, len(nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] == target: return mid if nums[mid] < target: left = mid + 1 else: right = mid - 1 return -110. 左边界模板
Java
int left = 0, right = nums.length; while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] >= target) right = mid; else left = mid + 1; } return left;C++
int left = 0, right = nums.size(); while (left < right) { int mid = left + (right - left) / 2; if (nums[mid] >= target) right = mid; else left = mid + 1; } return left;Go
left, right := 0, len(nums) for left < right { mid := left + (right-left)/2 if nums[mid] >= target { right = mid } else { left = mid + 1 } } return leftPython
left, right = 0, len(nums) while left < right: mid = left + (right - left) // 2 if nums[mid] >= target: right = mid else: left = mid + 1 return left六、二叉树
11. DFS 递归模板
Java
void dfs(TreeNode root) { if (root == null) return; dfs(root.left); dfs(root.right); }C++
void dfs(TreeNode* root) { if (!root) return; dfs(root->left); dfs(root->right); }Go
func dfs(root *TreeNode) { if root == nil { return } dfs(root.Left) dfs(root.Right) }Python
def dfs(root): if not root: return dfs(root.left) dfs(root.right)12. BFS 层序遍历模板
Java
Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while (!queue.isEmpty()) { int size = queue.size(); for (int i = 0; i < size; i++) { TreeNode node = queue.poll(); if (node.left != null) queue.offer(node.left); if (node.right != null) queue.offer(node.right); } }C++
queue<TreeNode*> q; q.push(root); while (!q.empty()) { int size = q.size(); while (size--) { auto node = q.front(); q.pop(); if (node->left) q.push(node->left); if (node->right) q.push(node->right); } }Go
q := []*TreeNode{root} for len(q) > 0 { size := len(q) for i := 0; i < size; i++ { node := q[0] q = q[1:] if node.Left != nil { q = append(q, node.Left) } if node.Right != nil { q = append(q, node.Right) } } }Python
from collections import deque q = deque([root]) while q: for _ in range(len(q)): node = q.popleft() if node.left: q.append(node.left) if node.right: q.append(node.right)13. 最近公共祖先模板
Java
TreeNode lca(TreeNode root, TreeNode p, TreeNode q) { if (root == null || root == p || root == q) return root; TreeNode left = lca(root.left, p, q); TreeNode right = lca(root.right, p, q); if (left != null && right != null) return root; return left != null ? left : right; }C++
TreeNode* lca(TreeNode* root, TreeNode* p, TreeNode* q) { if (!root || root == p || root == q) return root; TreeNode* left = lca(root->left, p, q); TreeNode* right = lca(root->right, p, q); if (left && right) return root; return left ? left : right; }Go
func lca(root, p, q *TreeNode) *TreeNode { if root == nil || root == p || root == q { return root } left := lca(root.Left, p, q) right := lca(root.Right, p, q) if left != nil && right != nil { return root } if left != nil { return left } return right }Python
def lca(root, p, q): if not root or root == p or root == q: return root left = lca(root.left, p, q) right = lca(root.right, p, q) if left and right: return root return left or right七、回溯
14. 全排列模板
Java
void backtrack(List<Integer> path, boolean[] used) { if (path.size() == nums.length) { ans.add(new ArrayList<>(path)); return; } for (int i = 0; i < nums.length; i++) { if (used[i]) continue; used[i] = true; path.add(nums[i]); backtrack(path, used); path.remove(path.size() - 1); used[i] = false; } }C++
void dfs(vector<int>& path, vector<int>& used) { if (path.size() == nums.size()) { ans.push_back(path); return; } for (int i = 0; i < nums.size(); i++) { if (used[i]) continue; used[i] = 1; path.push_back(nums[i]); dfs(path, used); path.pop_back(); used[i] = 0; } }Go
var dfs func() dfs = func() { if len(path) == len(nums) { tmp := append([]int{}, path...) ans = append(ans, tmp) return } for i := 0; i < len(nums); i++ { if used[i] { continue } used[i] = true path = append(path, nums[i]) dfs() path = path[:len(path)-1] used[i] = false } }Python
def dfs(): if len(path) == len(nums): ans.append(path[:]) return for i in range(len(nums)): if used[i]: continue used[i] = True path.append(nums[i]) dfs() path.pop() used[i] = False八、动态规划
15. 一维 DP 模板
Java
int[] dp = new int[n + 1]; dp[0] = 0; for (int i = 1; i <= n; i++) { dp[i] = ...; } return dp[n];C++
vector<int> dp(n + 1, 0); for (int i = 1; i <= n; i++) { dp[i] = ...; } return dp[n];Go
dp := make([]int, n+1) for i := 1; i <= n; i++ { dp[i] = 0 } return dp[n]Python
dp = [0] * (n + 1) for i in range(1, n + 1): dp[i] = 0 return dp[n]16. 最长公共子序列 二维 DP 模板
Java
int m = text1.length(), n = text2.length(); int[][] dp = new int[m + 1][n + 1]; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (text1.charAt(i - 1) == text2.charAt(j - 1)) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } } return dp[m][n];C++
int m = text1.size(), n = text2.size(); vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0)); for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { if (text1[i - 1] == text2[j - 1]) dp[i][j] = dp[i - 1][j - 1] + 1; else dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]); } } return dp[m][n];Go
m, n := len(text1), len(text2) dp := make([][]int, m+1) for i := range dp { dp[i] = make([]int, n+1) } for i := 1; i <= m; i++ { for j := 1; j <= n; j++ { if text1[i-1] == text2[j-1] { dp[i][j] = dp[i-1][j-1] + 1 } else if dp[i-1][j] > dp[i][j-1] { dp[i][j] = dp[i-1][j] } else { dp[i][j] = dp[i][j-1] } } } return dp[m][n]Python
m, n = len(text1), len(text2) dp = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): if text1[i - 1] == text2[j - 1]: dp[i][j] = dp[i - 1][j - 1] + 1 else: dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]) return dp[m][n]九、开发岗最该背熟的模板
如果时间有限,只背下面这些:
哈希表查找
前缀和
滑动窗口
单调队列
反转链表
快慢指针
单调栈
堆 Top K
二分查找
DFS / BFS
回溯模板
一维 DP / 二维 DP
十、面试时最容易写挂的点
Java
List和数组互转不熟PriorityQueue默认小顶堆Deque的push/pop/peek和offer/poll/peek混用
C++
unordered_map和map混淆priority_queue默认大顶堆指针判空和引用使用不稳
Go
切片扩容和截断容易写错
heap.Interface不熟map 默认零值逻辑容易漏
Python
列表浅拷贝写错
递归回溯忘记
path[:]heapq只有小顶堆
十一、复习建议
不要试图背 60 道题的完整代码
要背的是“题型骨架”
同类题共用一套模板,速度会快很多
- 面试前至少手写一遍:
滑动窗口
链表翻转
二叉树遍历
回溯
DP
如果你只能准备一门语言,就把你的主语言模板练到闭眼能写。
