程序员老鬼

杀人诛心!推荐的面试候选人,连一道最基础的“三数求和(3 Sum)”题都无法完成。因此,我们决定也为你重新安排一次技术面试~

真有点杀人诛心那味儿了。

网友说自己推荐了个面试候选人,结果人家技术面一上来,连“三数求和”这种基础算法题都没写出来。正常流程吧,也就候选人挂了,推荐人尴尬一下,事儿差不多过去了。

结果公司这边更狠,直接反手一句:我们现在开始怀疑你的判断能力,也怀疑你当初到底怎么评估这个人的。所以,别光他面了,你也重新来一轮技术面试吧。

Image

推荐失败不可怕,可怕的是领导突然发现,问题可能不在候选人身上,而在“你怎么敢推荐他”。本来以为自己是帮朋友递个简历,最后变成自己也被拉进考场。HR看完都得沉默,程序员看完背后一凉。

以后内推真别随便拍胸脯,尤其技术岗。你以为是送人情,别人可能当场给你开个回旋镖。

今日面试题

这个题第一眼别急着写排序。

“回答率最高”这几个字,坑就埋在分母里。不是看哪个问题回答次数最多,也不是看 answerId 有没有值,而是:

回答率 = answer 次数 / show 次数

线上这种日志表一般长这样:

uid  action  question_id
1    show    101
1    answer  101
2    show    101
3    show    102
3    answer  102
4    show    102
4    answer  102

问题 101 被展示 2 次,回答 1 次,回答率 1/2。

问题 102 被展示 2 次,回答 2 次,回答率 2/2。

所以答案是 102。

这里我一般不先算小数。小数有精度问题,虽然这题数据量不一定大,但没必要给自己找事。比较 a/b 和 c/d,直接比较 a*d 和 c*b 就行。

Java 写法可以这样:

import java.util.*;

classSolution{

staticclassLog{
int questionId;
        String action;

        Log(int questionId, String action) {
this.questionId = questionId;
this.action = action;
        }
    }

publicintgetHighestAnswerRateQuestion(List<Log> logs){
        Map<Integer, int[]> stat = new HashMap<>();

for (Log log : logs) {
int[] bucket = stat.computeIfAbsent(log.questionId, k -> newint[2]);

if ("show".equals(log.action)) {
                bucket[0]++;
            } elseif ("answer".equals(log.action)) {
                bucket[1]++;
            }
        }

int bestQuestion = -1;
int bestAnswer = -1;
int bestShow = 1;

for (Map.Entry<Integer, int[]> entry : stat.entrySet()) {
int questionId = entry.getKey();
int show = entry.getValue()[0];
int answer = entry.getValue()[1];

if (show == 0) {
continue;
            }

if (bestQuestion == -1
                    || answer * bestShow > bestAnswer * show
                    || answer * bestShow == bestAnswer * show && questionId < bestQuestion) {
                bestQuestion = questionId;
                bestAnswer = answer;
                bestShow = show;
            }
        }

return bestQuestion;
    }
}

这段代码里,int[0] 放展示次数,int[1] 放回答次数。别看数组不如对象优雅,算法题里够用了,少写一堆没意义的类。

真正要注意的是这行:

answer * bestShow > bestAnswer * show

它避开了除法。

如果写成:

answer / show

那就直接翻车了,Java 里两个整数相除还是整数。1 / 2 结果是 0,不是 0.5。

如果强转成 double 当然也能做:

double rate = answer * 1.0 / show;

但我不太爱这么写。比较比例,本来就可以用交叉相乘,干净。

还有一个边界要挡一下:有些问题可能只有 answer 日志,没有 show 日志。正常业务不该这样,但日志题别太相信数据干净。所以 show == 0 直接跳过。

最后如果两个问题回答率一样,我这里返回 questionId 更小的那个。面试时这个规则最好问一句;没给规则,就自己写稳定一点,别让结果飘。