某军工研究所网友爆料:一个月加班接近 20个小时,被同事警告说加班太少。。
刚看到个贴子,说某军工所的网友一个月加班不到20小时,结果被同事“善意警告”说太少了。底下还有网友补刀:我们这边都是60、70小时起步……无语住了。
有些单位把加班当忠诚度考核,甚至当成竞争筹码,不卷不行。
军工确实任务重、节奏快,可再怎么忙也得有人性边界吧。把加班当基本操作,只会恶性循环,该干的活没变,内耗情绪倒是涨了。
从我的角度看,不怕加班,就怕把“加班文化”当成正确答案。
还是希望大家都能在努力和生活之间找到平衡。工作再重要,也得给自己留口气。愿每个人都能少点被动卷,多点自愿干,心态稳,生活也能稳。【备注:文末可领最新资料】
面试题:2016年的投资
这题其实本质不难,就是名字听起来有点“金融大佬”那味儿😂,我们先把题目用人话说清楚,再慢慢用 Python 拼出算法。
有一张 Insurance 表,大概长这样
pid:投保人编号(主键,唯一)tiv_2015:这个人 2015 年一共投了多少钱tiv_2016:这个人 2016 年投了多少钱lat:所在城市纬度lon:所在城市经度
要干的事是:把 2016 年“成功投资”的金额加起来,保留两位小数。
一个人算“成功投资”,要同时满足两个条件:
他的 tiv_2015至少和别的某一个人是一样的(也就是说,这个 2015 投保额在表里出现次数 ≥ 2)他的城市是“独一份”的,也就是 (lat, lon)这个坐标在表里只出现一次
满足这俩条件的人,把他们的 tiv_2016 全部加起来,最后保留两位小数就行。
原题一般用 SQL 写,这里我们换个角度,用“算法 + Python”来搞。
算法思路拆一拆
你可以把这题当成一个“两次统计 + 一次筛选”的小数据处理题。
直觉版本是这样:
先遍历一遍所有记录
数一数每个 tiv_2015出现了几次再数一数每个 (lat, lon)出现了几次 这个最自然的结构就是哈希表(Python 里的dict)
再遍历一遍
它的 tiv_2015对应的计数是不是 ≥ 2它的 (lat, lon)对应计数是不是 == 1
对于每条记录,看:
两个条件都成立,就把它的
tiv_2016加进总和里
最后 round(总和, 2),就完成了
时间复杂度就是两遍遍历 O(n),空间就是两个哈希表,也是 O(n) 级别,很稳。
用 Python 写一个“纯算法版”
先假定我们把一行数据读成一个 dict,类似这样:
record = {
"pid": 1,
"tiv_2015": 10.0,
"tiv_2016": 5.0,
"lat": 10.0,
"lon": 10.0
}
整张表就是一个 list[dict]:
records = [
{"pid": 1, "tiv_2015": 10.0, "tiv_2016": 5.0, "lat": 10.0, "lon": 10.0},
{"pid": 2, "tiv_2015": 20.0, "tiv_2016": 20.0, "lat": 20.0, "lon": 20.0},
...
]
然后实现函数:
from collections import defaultdict
from typing import List, Dict, Any
definvestment_2016(records: List[Dict[str, Any]]) -> float:
"""
计算 2016 年成功投资金额总和,保留两位小数。
records: 每一项是一个 dict,包含
pid, tiv_2015, tiv_2016, lat, lon
"""
# 1. 统计 2015 投保额出现次数
cnt_2015 = defaultdict(int)
# 2. 统计城市坐标出现次数
cnt_city = defaultdict(int)
for r in records:
tiv_2015 = r["tiv_2015"]
lat = r["lat"]
lon = r["lon"]
cnt_2015[tiv_2015] += 1
cnt_city[(lat, lon)] += 1
# 3. 第二遍筛选 & 求和
total = 0.0
for r in records:
tiv_2015 = r["tiv_2015"]
lat = r["lat"]
lon = r["lon"]
tiv_2016 = r["tiv_2016"]
# 条件1:2015 年投保额,至少和别人一样一次
cond_2015 = cnt_2015[tiv_2015] >= 2
# 条件2:城市坐标是独一份
cond_city = cnt_city[(lat, lon)] == 1
if cond_2015 and cond_city:
total += tiv_2016
# 4. 四舍五入到两位小数
return round(total, 2)
if __name__ == "__main__":
example = [
{"pid": 1, "tiv_2015": 10, "tiv_2016": 5, "lat": 10, "lon": 10},
{"pid": 2, "tiv_2015": 20, "tiv_2016": 20, "lat": 20, "lon": 20},
{"pid": 3, "tiv_2015": 10, "tiv_2016": 30, "lat": 20, "lon": 20},
{"pid": 4, "tiv_2015": 10, "tiv_2016": 40, "lat": 40, "lon": 40},
]
print(investment_2016(example)) # 输出 45.0
你可以对照一下示例数据:
tiv_2015 = 10的有 pid=1,3,4,确实“至少有一个人跟我一样”,所以条件1 对他们都成立但城市坐标
(20, 20)出现了两次(pid=2,3),所以 pid=2 和 pid=3 的城市不是独一份pid=2:条件1 不成立(2015=20 只有他一个),条件2 也不成立(城市重复) pid=3:条件1 成立(2015=10),条件2 不成立(城市重复) 只有 pid=1 和 pid=4 同时满足两个条件,所以
tiv_2016是 5 + 40 = 45
上面代码跑出来 45.0,就对上题目的示例结果了([CSDN博客][1])。
顺便和 SQL 的思路对个频
原题在 SQL 里一般会用两次 GROUP BY:
一次按 tiv_2015分组,找出出现次数 ≥ 2 的金额一次按 (lat, lon)分组,找出出现次数 == 1 的城市然后把这两个结果跟原表“联立”,最后 SUM(tiv_2016)
你会发现,我们刚才用 Python 的两张哈希表,其实就是把这两个 GROUP BY 的结果“缓存”在内存里了,然后在第二次遍历里做“过滤 + 求和”。
所以这题本质上不是什么高深算法,就是一个很标准的“两次扫描 + 计数 + 过滤”套路: 以后碰到类似“满足若干全局条件,再把某个字段加起来”的题,大概率都可以用这一套模板来写 Python 版。
如果你后面想再扩展,比如用 pandas 来写一个更“表格化”的版本,也可以在这个思路上直接平移过去:groupby 两次、打标记、再过滤求和就行了。
-END-
我为大家打造了一份RPA教程,完全免费:songshuhezi.com/rpa.html
虎哥作为一名老码农,整理了全网最全《python高级架构师资料合集》,总量高达650GB