快手java面经

2020-09-05  本文已影响0人  一个IT人

写在前面

快手面试还算是简单一些,人性化一些,更多的是考虑技术选型,比如多种MQ的优缺点,未来如何做技术选型等。

一面

    快手的第一面聊的时间久些,历时1小时45分钟,主要是把我工作多年的4个大项目都详细的聊一下

项目

所问的项目,基本套路就是:为了解决什么业务做了什么样的架构设计,其中遇到了什么难点和亮点。你可以围绕高并发、高性能、稳定性、可靠性、一致性等等描述一下你的亮点...

技术

1、技术选型    

        double与grpc的对比

这里回答的不太好,没了解过grpc,回答的double与springcloud区别

redis与memcached

从存储结构、持久化等对比,重点讲的是redis的知识

rocketmq与kafka

这里回答的也不好,对比的少,介绍rocket的较多,rocket的发送端可靠性、服务端可靠性、消费端可靠性,注册中心、事务等

 2、基础知识

Executors 与 ThreadPoolExecutor的选择,为什么选择后者

1、可读性强,便于开发与合作

2、重点是线程的数量和阻塞队列可控,并不会轻易导致线程无限分配抢占所有cpu和内存泄漏等问题


redis的list结构压缩表和跳表

算法

问题

数组里引用数组,死循环后break

输入

A : a,b,c,B

B: C, c

C: A,

输出

A: a,b,c,c

B: a,b,c,c

C:  a , b, c,c

isGroup()

Map<String, Set<String>>

public void convert(Map<String, Set<String>> data) {

}

我的解题算法,感觉写的并不是很好

public static void main(String[] args) {

    Map<String, Set<String>> va = new HashMap();

    Set<String> A = new HashSet<>();

    A.add("a");

    A.add("b");

    A.add("c");

    A.add("B");

    va.put("A", A);

    Set<String> B = new HashSet<>();

    B.add("C");

    B.add("c");

    va.put("B", B);

    Set<String> C = new HashSet<>();

    C.add("A");

    va.put("C", C);

    va.forEach((s, values) ->{

        Map<String, List<String>> temp = new HashMap();

        getValue2(va, temp, s, values);

        System.out.println(s + ":" + JSONObject.toJSONString(temp.get(s)));

    });

}

private static void getValue2(Map<String, Set<String>> va, Map<String, List<String>> temp, String key,

                              Set<String> value) {

    if (temp.containsKey(key)) {

        return;

    }

    temp.put(key, null);

    List<String> list = new ArrayList<>();

    value.forEach(s ->{

        if (!s.equals(s.toLowerCase())) {// 大写的字母的时候

            if (temp.get(s) == null) {

                getValue2(va, temp, s, va.get(s));

            }

            if (temp.get(s) != null) {

                list.addAll(temp.get(s));

            }

        } else {//小写的字母直接加减

            list.add(s);

        }

    });

    temp.put(key, list);

}

二面

二面就没问业务,上来就是技术的问题,历时1:30分钟

技术

1、mq,遇到过什么问题,怎么解决的?offset对于失败的消息如何记录

2、redis 内存击穿,如何存储空值以节省空间

    1.Redis 集合(Set)

    2.位图存储

    3.布隆过滤器

3、set的结构,在使用的时候有什么问题

4、JVM:OOM的问题排查,CMS收集器

设计题

请设计一个服务上云的方案

    需要考虑3点1.web  2.redis  3.mysql

数据迁移的过程中,考虑好一些碰撞,和存量数据和增量数据的处理。

算法

表达式计算,数字的加减乘除

int calculate(String exp)

        正整数,+ - * /,

        int calculate(String exp)

        exp = "(3-2)*12+3*3*2"

        Positive integer, + - *,

这道题其实压栈的思想

思路:

1. 如果碰到数字, 则把数字入栈

2. 如果碰到空格, 则继续下一步

3. 如果碰到 '+' '-' '*' '/', 则查找下一个数字num

    A.如果是'+', 下一个数字num直接入栈

    B.如果是'-',-num入栈

    C.如果是'*', num = stack.pop() * num, 入栈

    D.如果是'/', num = stack.pop() / num, 入栈

4. 最后,把栈里的数相加就是结果

public int calculate(String s) {

    char[] cs = s.trim().toCharArray();

    Stack<Integer> st = new Stack();

    int ans= 0, i= 0;

    while (i< cs.length) {

        if (cs[i] == ' ') {

            i++;

            continue;

        }

        char tmp = cs[i];

        if (tmp == '*' || tmp == '/' || tmp == '+' || tmp == '-') {

            i++;

            while (i< cs.length && cs[i] == ' ') { i++; }

}

        int num= 0;

        while (i< cs.length && Character.isDigit(cs[i])) {

            num= num* 10 + cs[i] - '0';

            i++;

        }

        switch (tmp) {

            case '-':

                num= -num;

                break;

            case '*':

                num= st.pop() * num;

                break;

            case '/':

                num= st.pop() / num;

                break;

            default:

                break;

        }

        st.push(num);

    }

    while (!st.isEmpty()) { ans+= st.pop(); }

    return ans;

}

三面


技术题


1、redis集群主从方式,主机down机的处理,与memcache的区别,key的失效策略

2、rocketmq与kafaka的区别

3、nago协议和inode

设计与算法题

1、767的阶乘后边有多少个0

可以➗5的,25里有2个5

static int factorial(int num) {

    int result= 0;

    for (int i= 1; i<= num; i++) {

        /*

//方法1

if (i % 5 == 0) {

result++;

int temp = i / 5;

while (temp % 5 == 0) {

result++;

temp = temp / 5;

}

}*/

        if (i% 5 == 0) {

            int temp= i;

            do {

                result++;

                temp= temp/ 5;

            } while (temp% 5 == 0);

        }

}

    return result;

}

public static void main(String[] args) {

    System.out.println(factorial(26));

}

2、大文件1G ,每个词条16字节,1M内存,求出词频最高的100条数据

    由于内存的限制,所以不能同时将1G的文件进行分析计算,可以使用分而治之的思想,将文件分为多个,可以分为某一个只有1M的,这样将小文件的计算就不会出现超出内存的问题了。

    分隔的方法就是将每一个单词进行hash后,hash%5000这样将单词分割到5000个小文件里,1G/5000大约一个文件200k,重复单词一定被分割到同一个文件中。

    由于没一项是一个单词,可以采用字典树Trie进行统计/hashmap,统计每个文件中出现的次以及频率。字典树的时间复杂度为单词最长的数值+遍历一遍n*O(k),hash为遍历一遍+产生hash+冲突解决

    对每一个小文件取出其中频率最大的前100个单词,然后进行合并,或者直接进行归并排序/堆排序,nlog(k)

问答环节

    基本上是我来问了,问一问部门的业务,用到什么的技术,有什么苦难和瓶颈?

HR

一些基本问题,工作表现,个人的优缺点,遇到过什么问题,怎么解决的

上一篇下一篇

猜你喜欢

热点阅读