程序员老鬼

上个月空降了个总监,听说200万从某大厂挖来的,他一来要大换血。团队开始站队:一波人疯狂表忠心,一波人消极抵抗,我选择观望。

刚看到个贴子,说公司空降了个年薪两百万的总监,上来就要动大手术。原团队一部分人赶紧表态,恨不得把忠诚写脸上;一部分人直接摆烂,楼主夹在中间先看戏。

结果三个月一盘点:表忠心的确被“提拔”了,但全是又累又脏的活;硬刚的那拨人,话不多说,慢慢被晾一边了。

Image

网友们的回复我看了看,有人说“职场就该会站队”,有人让楼主赶紧跑,还有人骂领导是PUA体质。

怎么说呢,我的看法是:站不站队是其次,先想清楚自己能提供什么价值。你没本事的时候,站谁那队都容易被当工具人;你有本事的时候,其实是别人来争着拉你进队。

换个角度想,空降领导来也要做业绩,他最需要的是“能干事、少惹事、关键时刻靠得住”的人,而不是只会喊口号的。与其急着表忠,或者赌气对着干,不如悄悄把自己的专业干硬,把底线守住,把选项留在自己手里。

面试题:每件商品的最新订单

我昨晚十一点多还在工位上磨这道题,饿得前胸贴后背,结果被产品经理一句话整清醒了: “东哥,我就想在后台上看到,每个商品最近一笔订单是啥,别给我整那些复杂报表。”

你们看,其实这道算法题翻译成人话就一句: 有一堆订单记录,每条上面有商品ID、下单时间啥的,要把每个商品“最新的一单”挑出来。

先把数据长啥样说清楚

脑子里先有个画面,不然写代码很抽象。比如我们有个订单列表:

订单1:productId = 1001, time = 10:01
订单2:productId = 1002, time = 10:05
订单3:productId = 1001, time = 10:08
订单4:productId = 1002, time = 09:59
...

那结果应该是:

  • 商品 1001 → 选时间 10:08 的那条
  • 商品 1002 → 选时间 10:05 的那条

也就是说,每个 productId 只留一条,时间最大那条。

我见我们组小李一开始写的是这种思路: 对每个商品,把所有订单再扫一遍,找时间最大的。

伪代码差不多这样(别抄啊,这个是“反例”):

for (每个商品 p) {
    latest = null;
for (每个订单 o) {
if (o 的商品是 p 且 时间更新) {
            latest = o;
        }
    }
}

问题也很明显: 订单有 n 条,商品有 m 个,这么一套下来时间复杂度 O(n * m),数据一大,服务器就开始喘粗气了。

线上的量级,谁敢这么写,监控一看QPS掉了,半夜就得被电话叫起来挨打。

正常人写法:扫一遍就搞定

你想啊,其实对每个商品,我们只需要记住“目前看到的最新那单”。 新的订单进来,只要比它晚,就把旧的替换掉。

所以更合理的做法是:

  • 准备一个 Map<productId, 最新订单>

  • 顺序扫描所有订单:

    • map 里还没有这个商品:直接放进去
    • map 里已经有了:比较一下时间,新的更晚就替换

一趟搞定,时间复杂度 O(n),空间复杂度 O(m),非常稳。

先整一个订单类,简单点就行:

import java.time.LocalDateTime;

publicclassOrder{
private Long orderId;
private Long productId;
private LocalDateTime orderTime;

publicOrder(Long orderId, Long productId, LocalDateTime orderTime){
this.orderId = orderId;
this.productId = productId;
this.orderTime = orderTime;
    }

public Long getOrderId(){
return orderId;
    }

public Long getProductId(){
return productId;
    }

public LocalDateTime getOrderTime(){
return orderTime;
    }

@Override
public String toString(){
return"Order{" +
"orderId=" + orderId +
", productId=" + productId +
", orderTime=" + orderTime +
'}';
    }
}

主逻辑用最直白的写法先来一版:

import java.time.LocalDateTime;
import java.util.*;

publicclassLatestOrderDemo{

publicstatic Map<Long, Order> findLatestOrderByProduct(List<Order> orders){
// key: 商品ID, value: 当前看到的最新订单
        Map<Long, Order> latestMap = new HashMap<>();

for (Order order : orders) {
            Long productId = order.getProductId();
            Order cur = latestMap.get(productId);
if (cur == null) {
// 第一次见到这个商品
                latestMap.put(productId, order);
            } else {
// 比较下单时间,谁更新要谁
if (order.getOrderTime().isAfter(cur.getOrderTime())) {
                    latestMap.put(productId, order);
                }
            }
        }

return latestMap;
    }

publicstaticvoidmain(String[] args){
        List<Order> list = Arrays.asList(
new Order(1L, 1001L, LocalDateTime.parse("2024-01-01T10:01:00")),
new Order(2L, 1002L, LocalDateTime.parse("2024-01-01T10:05:00")),
new Order(3L, 1001L, LocalDateTime.parse("2024-01-01T10:08:00")),
new Order(4L, 1002L, LocalDateTime.parse("2024-01-01T09:59:00"))
        );

        Map<Long, Order> latest = findLatestOrderByProduct(list);
        latest.forEach((pid, o) -> System.out.println("商品 " + pid + " 最新订单:" + o));
    }
}

这个跑出来,控制台会打印类似:

商品 1001 最新订单:Order{orderId=3, ...}
商品 1002 最新订单:Order{orderId=2, ...}

就达标了,对吧,很朴素,但是够用。

要是你喜欢 Java 8 的味道,也可以这么玩

有时候面试官会问:“能不能用 stream 写一下?” 其实就是把上面的逻辑塞进 Collectors.toMap 的合并函数里:

import java.util.function.Function;
import java.util.stream.Collectors;

publicstatic Map<Long, Order> findLatestOrderByProductStream(List<Order> orders){
return orders.stream()
            .collect(Collectors.toMap(
                    Order::getProductId,         // key: 商品ID
                    Function.identity(),         // value: 当前这条订单
                    (o1, o2) ->                  // key 冲突时的合并逻辑
                            o1.getOrderTime().isAfter(o2.getOrderTime()) ? o1 : o2
            ));
}

这里有个小点很多人一开始会写错:toMap 如果 key 冲突,你不写第三个参数,它是会直接抛异常的,不会默默帮你选一个。 所以合并函数一定要写清楚,“旧订单 vs 新订单,谁时间晚要谁”。

-END-

我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html

最后给大家分享一份不错的副业资料,点击下方公众号,回复关键字: 副业 领,也可以链接我微信:hls404