“算法王国闯关挑战赛”​​ 的故事

6 阅读6分钟

以下用一场 ​​“算法王国闯关挑战赛”​​ 的故事,结合 ​​Java代码​​ 和 ​​高频题型分类​​,带你通关大厂面试最常考的算法题!每个题型附核心思路、代码模板和实战例题(数据来自2024年大厂真题统计)👇


🏔️ ​​第一关:数组山谷(数组与字符串)​

​剧情​​:你是一名登山者,在数字山谷中寻找宝藏(目标值),但山路崎岖(数据无序),还有毒蛇(重复元素)挡路!
​高频题​​:

  1. ​两数之和(出现频率:90%)​

    • ​故事​​:找到两座山峰高度和等于目标值,避免跌落悬崖。
    • ​解法​​:哈希表记录已路过山峰高度,遇新峰时查补数。
    java
    Copy
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            int complement = target - nums[i];
            if (map.containsKey(complement)) {
                return new int[]{map.get(complement), i};
            }
            map.put(nums[i], i);
        }
        return new int[0];
    }
    // 时间复杂度:O(n),空间:O(n) [1](@ref)
    
  2. ​滑动窗口最大值(出现频率:70%)​

    • ​故事​​:在狭窄山路上,你只能看到连续K步内的最高峰。
    • ​解法​​:单调队列维护窗口内递减序列。
    java
    Copy
    public int[] maxSlidingWindow(int[] nums, int k) {
        Deque<Integer> deque = new ArrayDeque<>();
        int[] res = new int[nums.length - k + 1];
        for (int i = 0; i < nums.length; i++) {
            // 队尾小于当前值则弹出
            while (!deque.isEmpty() && nums[i] >= nums[deque.peekLast()]) {
                deque.pollLast();
            }
            deque.offerLast(i);
            // 队首是否在窗口外
            if (deque.peekFirst() <= i - k) deque.pollFirst();
            // 记录窗口最大值
            if (i >= k - 1) res[i - k + 1] = nums[deque.peekFirst()];
        }
        return res;
    }
    // 时间:O(n),空间:O(k) [1,3](@ref)
    

🌲 ​​第二关:链表森林(链表操作)​

​剧情​​:穿越迷雾森林,藏宝图(链表)被加密,有的路线成环(循环链表),有的需要翻转(反转链表)!
​高频题​​:

  1. ​反转链表(出现频率:85%)​

    • ​故事​​:将藏宝图路线从尾到头重新连接。
    • ​解法​​:三指针轮转(prev, cur, next)。
    java
    Copy
    public ListNode reverseList(ListNode head) {
        ListNode prev = null, cur = head;
        while (cur != null) {
            ListNode next = cur.next;
            cur.next = prev;  // 翻转箭头
            prev = cur;       // 前移prev
            cur = next;       // 前移cur
        }
        return prev;  // 新头节点
    }
    // 时间:O(n),空间:O(1) [2,6](@ref)
    
  2. ​环形链表检测(出现频率:80%)​

    • ​故事​​:森林中有环形陷阱,用快慢指针逃离(快指针走2步,慢指针走1步)。
    java
    Copy
    public boolean hasCycle(ListNode head) {
        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;
    }
    // 时间:O(n),空间:O(1) [6,7](@ref)
    

🧩 ​​第三关:动态规划迷宫(DP问题)​

​剧情​​:迷宫中的金币(子问题)分散分布,你要在守卫(约束条件)巡逻下拿最多金币!
​高频题​​:

  1. ​背包问题(出现频率:75%)​

    • ​故事​​:背包容量有限,每块金币重量和价值不同,最大化总价值。
    • ​状态方程​​:dp[i][w] = max(不拿第i个, 拿第i个 + dp[i-1][w-weight[i]])
    java
    Copy
    public int knapSack(int W, int[] wt, int[] val) {
        int n = wt.length;
        int[][] dp = new int[n + 1][W + 1];
        for (int i = 1; i <= n; i++) {
            for (int w = 1; w <= W; w++) {
                if (wt[i-1] <= w) {
                    dp[i][w] = Math.max(
                        dp[i-1][w], 
                        val[i-1] + dp[i-1][w - wt[i-1]]
                    );
                } else {
                    dp[i][w] = dp[i-1][w];
                }
            }
        }
        return dp[n][W];
    }
    // 时间:O(n*W),空间:O(n*W) [5](@ref)
    
  2. ​股票买卖(出现频率:70%)​

    • ​故事​​:每天宝石价格波动,低买高卖赚差价(可多次交易)。
    • ​贪心解法​​:只要今天比昨天涨就卖出!
    java
    Copy
    public int maxProfit(int[] prices) {
        int profit = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] > prices[i-1]) {
                profit += prices[i] - prices[i-1];
            }
        }
        return profit;
    }
    // 时间:O(n),空间:O(1) [5](@ref)
    

🌳 ​​第四关:算法村庄(树与图)​

​剧情​​:村庄道路成树状,找最短送信路径(二叉树遍历),或识别家族关系网(图遍历)。
​高频题​​:

  1. ​二叉树层序遍历(出现频率:80%)​

    • ​故事​​:按家族辈分从上到下统计人口。
    • ​解法​​:队列实现BFS。
    java
    Copy
    public List<List<Integer>> levelOrder(TreeNode root) {
        List<List<Integer>> res = new ArrayList<>();
        if (root == null) return res;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            int size = queue.size();
            List<Integer> level = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                TreeNode node = queue.poll();
                level.add(node.val);
                if (node.left != null) queue.offer(node.left);
                if (node.right != null) queue.offer(node.right);
            }
            res.add(level);
        }
        return res;
    }
    // 时间:O(n),空间:O(n) [2,4](@ref)
    
  2. ​图的最短路径(Dijkstra算法)​

    • ​故事​​:用魔法飞毯(优先队列)快速找到村庄间最短路径。
    java
    Copy
    public int[] dijkstra(int[][] graph, int start) {
        int n = graph.length;
        int[] dist = new int[n];
        Arrays.fill(dist, Integer.MAX_VALUE);
        dist[start] = 0;
        PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> a[1] - b[1]);
        pq.offer(new int[]{start, 0});
        while (!pq.isEmpty()) {
            int[] node = pq.poll();
            int u = node[0];
            for (int v = 0; v < n; v++) {
                if (graph[u][v] != 0) {
                    int newDist = dist[u] + graph[u][v];
                    if (newDist < dist[v]) {
                        dist[v] = newDist;
                        pq.offer(new int[]{v, newDist});
                    }
                }
            }
        }
        return dist;
    }
    

🔍 ​​第五关:村长的特别挑战(其他高频题)​

  1. ​二分查找(出现频率:85%)​

    • ​故事​​:村长把宝藏钥匙藏在有序书页中,快速定位页码。
    java
    Copy
    public int search(int[] nums, int target) {
        int left = 0, right = nums.length - 1;
        while (left <= right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) return mid;
            else if (nums[mid] < target) left = mid + 1;
            else right = mid - 1;
        }
        return -1;
    }
    // 时间:O(log n),空间:O(1) [3,5](@ref)
    
  2. ​贪心算法:种花问题(出现频率:60%)​

    • ​故事​​:在花坛中隔一个坑种一朵花,最大化种植数。
    java
    Copy
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int count = 0;
        for (int i = 0; i < flowerbed.length && count < n; i++) {
            if (flowerbed[i] == 0 && 
                (i == 0 || flowerbed[i-1] == 0) && 
                (i == flowerbed.length-1 || flowerbed[i+1] == 0)) {
                flowerbed[i] = 1;
                count++;
            }
        }
        return count >= n;
    }
    // 时间:O(n),空间:O(1) [3](@ref)
    

💎 ​​高频算法题总结表(大厂面试Top 10)​

​题型​​高频题目​​出现频率​​核心思想​
数组/字符串两数之和、滑动窗口最大值90%哈希表、单调队列
链表反转链表、环形链表85%三指针、快慢指针
动态规划背包问题、股票买卖80%状态转移方程、空间优化
二叉树层序遍历、重建二叉树75%BFS、分治法
二分查找搜索旋转数组、找元素边界70%红蓝指针法
贪心算法种花问题、区间调度65%局部最优解
栈/队列最小栈、用栈实现队列60%双栈协作
Top K 元素、合并K个链表55%优先队列
位运算只出现一次的数字50%异或性质
设计题LRU缓存、循环队列45%哈希表+双向链表

🧠 ​​通关秘籍​

  1. ​先判题型​​:

    • 最值问题 → 想 ​​贪心​​ 或 ​​DP​
    • 子数组/子串 → ​​滑动窗口​​ 或 ​​前缀和​
    • 有序数据 → ​​二分查找​
    • 树/图路径 → ​​DFS/BFS​
  2. ​代码模板化​​:

    • 链表题:​​虚拟头节点 + 双指针​
    • DP题:​​定义状态 + 转移方程 + 初始化​
    • 树题:​​递归终止条件 + 左右子树处理​
  3. ​复杂度敏感​​:

    • 10^5 数据规模 → 必须 O(n log n) 以下解法
    • 看到“有序” → 想能否二分优化到 O(log n)

⚡ ​​终极建议​​:从 ​​LeetCode Hot 100​​ 和 ​​《剑指Offer》​​ 开始刷,每天2题坚持2个月,80%面试题可覆盖!遇到难题时默念:​​“分治拆解子问题,指针滑动空间换”​​ —— 算法面试,不过如此!