阿里P5初级算法面经:排序算法对比、链表操作、动态规划入门、LRU缓存实现

19 阅读6分钟

P8架构师聊完系统设计,这篇回到P5级别的数据结构与算法。算法是阿里面试第一关——P5必须过算法,面试官给一道LeetCode Medium,20分钟写完跑通,过不了后面都不用聊。

Android岗算法题集中在排序、链表、树、动态规划和缓存设计,难度Medium居多,要求讲清时间空间复杂度。

今天8道题覆盖P5算法核心考点,每道给出思路+代码+复杂度分析。

Q1:常见排序算法对比?Android开发用哪些?

快速排序:平均O(n log n),最坏O(n²)。选随机pivot避免最坏。空间O(log n)递归栈,不稳定。

归并排序:稳定O(n log n),空间O(n)。适合链表排序。

堆排序:O(n log n),空间O(1),不稳定。适合TopK问题。

Android实际:Collections.sort用TimSort(归并+插入混合),Arrays.sort用DualPivotQuickSort。面试考手写一般考快排和归并。

追问:快排为什么比归并常用?常数因子小——快排in-place不需要额外数组,实际运行比归并快2-3倍。但归并稳定(相等元素不交换位置),排序自定义对象时用归并更可靠。

Q2:链表反转怎么实现?迭代和递归都写一下

迭代法:三个指针prev/curr/next,遍历链表逐个反转next指向。时间O(n)空间O(1)。

ListNode reverse(ListNode head) {
    ListNode prev = null, curr = head;
    while (curr != null) {
        ListNode next = curr.next;
        curr.next = prev;
        prev = curr;
        curr = next;
    }
    return prev;
}

递归法:递归到末尾,回溯时反转next指向。时间O(n)空间O(n)递归栈。

追问:反转链表前N个节点怎么做?递归加计数器,到第N个停止反转,把第N+1节点接到反转后尾部。这个变体面试考得多。

Q3:判断链表有环?找环的入口节点?

判断有环:快慢指针。slow每次走一步,fast每次走两步。如果有环,fast一定会追上slow(在环里绕圈)。时间O(n)空间O(1)。

找入口:相遇后,把一个指针放回head,两个都每次走一步,下一次相遇就是环入口。证明:fast走了2倍距离,多走的恰好是环的整数倍,所以从head和相遇点同速走必然在入口相遇。

追问:两个链表相交怎么找交点?先算两链表长度差d,长链表先走d步,然后两个同时走,相遇点就是交点。或者更优雅:A走到末尾跳到B头,B走到末尾跳到A头,两者走的总距离一样,相遇点就是交点。

Q4:二叉树的层序遍历?怎么实现?

用队列实现BFS。每层处理时先记录队列当前大小(当前层节点数),循环size次弹出处理,处理时把子节点入队。

List<List<Integer>> levelOrder(TreeNode root) {
    List<List<Integer>> result = new ArrayList<>();
    Queue<TreeNode> queue = new LinkedList<>();
    if (root != null) 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);
        }
        result.add(level);
    }
    return result;
}

追问:判断二叉树对称?递归比较左右子树:isMirror(l, r)要求l.val==r.val且l的左子树跟r的右子树镜像。

Q5:动态规划入门?斐波那契怎么优化?

动态规划核心:把大问题拆成子问题,缓存子问题解避免重复计算。关键是找状态转移方程。

斐波那契:F(n) = F(n-1) + F(n-2)。递归O(2^n)大量重复。DP数组O(n)时间O(n)空间。空间优化:两个变量滚动,O(n)时间O(1)空间。

int fib(int n) {
    if (n <= 1) return n;
    int prev = 0, curr = 1;
    for (int i = 2; i <= n; i++) {
        int next = prev + curr;
        prev = curr;
        curr = next;
    }
    return curr;
}

追问:爬楼梯问题(每次1或2阶)跟斐波那契什么关系?完全一样——到第n阶的方法数 = 到第n-1阶 + 到第n-2阶。面试考爬楼梯就是考斐波那契DP。

Q6:背包问题怎么解?0-1背包和完全背包?

0-1背包:N个物品各有重量w和价值v,背包容量W,每个最多选一次。状态转移:dp[j] = max(dp[j], dp[j-w[i]] + v[i]),一维数组逆序遍历。

完全背包:每个物品可选无限次。状态转移一样但正序遍历。

Android关联:内存分配优化可建模为背包——有限空间选加载哪些模块使收益最大。

Q7:LRU缓存怎么实现?

LRU(Least Recently Used)淘汰最久未使用的元素。Android的LruCache就是LRU实现。

数据结构:HashMap + 双向链表。HashMap保证O(1)查找,双向链表维护访问顺序。

get操作:HashMap查找,命中后把节点移到链表头部。O(1)。

put操作:插入/更新,新节点放头部。超过容量删链表尾部(最久未用)并从HashMap移除。O(1)。

class LRUCache {
    int capacity;
    LinkedHashMap<Integer, Integer> map;
    LRUCache(int capacity) {
        this.capacity = capacity;
        map = new LinkedHashMap<>(capacity, 0.75f, true);
    }
    int get(int key) {
        return map.getOrDefault(key, -1);
    }
    void put(int key, int value) {
        map.put(key, value);
        if (map.size() > capacity) {
            map.remove(map.keySet().iterator().next());
        }
    }
}

追问:Java的LinkedHashMap怎么实现LRU?构造时传accessOrder=true,每次get/put会把节点移到链表末尾。重写removeEldestEntry返回size()>capacity就自动淘汰最老的。面试写LRU用LinkedHashMap三行代码搞定。

Q8:Android的LruCache原理?跟LRU缓存什么关系?

LruCache是Android提供的内存缓存工具类,底层就是LinkedHashMap实现LRU策略。

构造参数:maxSize(缓存大小上限,通常用字节数或条目数)。每次put后调trimToSize——如果超过maxSize就移除eldest条目。

典型用法:图片缓存。new LruCache<String, Bitmap>(maxMemory / 8) 缓存Bitmap对象,key是URL。命中直接返回不调网络/磁盘。

追问:LruCache和DiskLruCache区别?LruCache是内存缓存(快但App退出丢失),DiskLruCache是磁盘缓存(慢但持久化)。Glide三级缓存:ActiveResources → LruCache → DiskLruCache → 网络。


面试Tips:P5算法面试排序考快排和归并手写+复杂度分析。链表考反转/判环/相交(快慢指针是核心技巧)。树考层序遍历(BFS队列)。动态规划考斐波那契/爬楼梯/背包。LRU缓存考HashMap+双向链表实现。准备算法面试刷LeetCode Hot 100足够,Android岗不考Hard。

下一篇进入设计模式专项——单例五种写法、观察者模式、策略模式,这些在Android源码里到处都是。


面试被考过LRU手写的同学评论区举个手,你用的LinkedHashMap还是手写双向链表?

本系列连载中,关注不迷路,下一篇:阿里P6中级Android(设计模式专项)面试真题

系列简介:Android大厂面经连载,覆盖字节跳动、腾讯、阿里、美团等40+企业,从初级到架构师全岗位覆盖。每篇文章包含真实面试题+详细答案+代码示例,帮你拿到大厂Offer。