面试总结

时间:2018.10.14-2018.10.24

地点:广州

一、闲话

  18年刚毕业的我,签了一家桂林的公司,本来是图家近,并且以后会到南宁分公司去,这样逢年过节回家也方便。

  桂林是个好地方啊,物价低得简直像是在天堂,空气也都很好,风景优美。哪曾想却被坑的好苦,我是用的安卓简历去应聘的,校招,结果聊得还好,谁知道去之后竟然是让做小程序,那个主管也不懂技术,先做着吧,但是关键是整个部门就只有我在做软件。在做完之后主管假装好意得问我想学什么技术,可以调其他部门学习,我脱口而出区块链、架构、大数据。结果呵呵。插曲就是原先约定好的五千工资竟然被压榨成四千五,并且说希望我自己凭能力提上去,食屎啦你!后来我真去其他部门了,拧了一个多星期的螺丝钉,没错,是用螺丝刀拧的那种!发展方向估计是偏硬件方面。然后八月底提离职了,然后原主管就拖着我啊,说什么我走了项目没人接,需要找人,我TM!原则上试用期三天就能走人的,后来我是用了将近半个月。还好那十天工资发了,就是待了一个多月社保只交了一个月。

   原先我的方向是安卓开发,后来校招发现招安卓的真的是太少了,然后转战java,看了黑马的视频。桂林那段时间简直就是闭关,尤其是离职后的日子。我是9月10号离职,然后看日子,觉得至少该学个一两周吧,但是一周后就快到中秋了,中秋一周后就又到国庆了。。。然后就安心闭关吧,国庆后再去找工作。事实证明我是对的,因为过一遍黑马的视频并不是一两天就能办到的。泪奔。

   买的10月13号的动车,当天是周六,室友骑电动车搭我去车站,然而我真是有毒。其实入职前去了趟深圳求职java,从家去的路上遇上了道路塌方,错过火车,住宿的地方又吵,睡不安稳,吃了假早餐。。。。。我是中了砒霜的毒,并且在深圳的那一周是碰了一鼻子灰的,然后决定先回桂林工作了,有机会再出来。谁知道回去后第二天就接到复试通知了,含泪拒绝。刚才说到我有毒,因为室友送我的时候路上就下雨了,下大雨!我还是掐着点去的车站,时间不充裕,结果到站了雨就停了,还好赶上了火车。室友说他回去时发现家里都是干的,雨都没下过一样。。。。

  来到广州先是找住的地方,这边没什么男的朋友,而且上次去深圳感觉不找一个月应该是找不到工作的,所以怀揣着微薄的工资决定来一场持久战。

  来之前选好了地理位置,天河棠下。这边附近就是一个软件园区,属于城中村,租房便宜。原先在咸鱼看好了一个房子550元,家具齐全。但是到棠下后假装站着看租房公告栏,结果一堆人过来问租不租房,500的房子但是家具确实没咸鱼的全,然后决定再看看。但是在我看最后一家的时候,天都黑了,她把我带到了一个深巷中,我都不记得来时路,最后谈好了房价470,算是被坑了吧,但是转念一想,工作地点还不确定,可能会换,不如先租个便宜点的。

  周六就这样过去了。周天投了一波简历,没人睬,有点失望。

  转机在周一,估计hr们上班了。本来接到第一个面试的时候推到了周二,结果我还真是正确的,周一一共接到了五家面试,面试排到了周四。。。。

  但是一直到周四,都没有再接到其他面试,好无语。这一周就笔试面试来说都不是很好,唯独有一家笔试七十多,面试的两个人技术还不怎么的,他们公司做的挺多项目,见我既会安卓、java,又会小程序、php、h5,觉得很对口,然后就查我背景了,可是我留的是我室友的电话。。。但是他们还是提出要复面了。可是看准网上他们公司的评价真的是贼强!瞬间拒绝复试!

  第二周似乎转运了,周六周天投了一波简历,周一又收到面试,但是我照例推到了周二。周二一共面了三家,第一家是一个今年八月刚起步的小公司,我说我初级他瞬间想让我走,然后让我做了套卷子,全是框架题,并且如果框架了解的不是特别深入的话,确实不好答,还有就是sql题。

  下午第一家是做微信小游戏的,老板很时尚,做的后端,hr小姐姐热情,另一个小姐姐很漂亮,你懂得。初试老板就跟我谈好了薪资6k,其实面试了这么多家,薪资实际上5.5k这样,有一家说6k左右,其实他的意思根本没有右,是低于6k。所以对于我这种游戏白痴来说,给我6k不错了。而且我也急于稳定一下(其实是小姐姐真的很漂亮),主要一点是公司离住所只需走路十五分钟。

  下午最后一家公司才是我最想去的,面试官问了就简历先是问了一些项目的问题,然后问了设计模式,数据库优化等等。但是来的时候我接到了另一个offer,我从没想过那家公司会录取我,笔试59分,面试一般般,喊的7.5k,要我当天决定要不要去,被我推迟了一天。所以这家公司面试的时候还是很放松的,老子有offer了(得意)。技术面完,hr小姐姐介绍了下公司和福利,公司技术大牛,哇,瞬间觉得应该来这,但是ceo去校招了,周五才能回来,天意啊。

  最后我去了59分的那家。

  深圳的面试面的比较深,会问框架原理,广州问的都是基础题和简历上的项目,接下来总结下笔试吧。

二、笔试总结

1、笔试选择题基本上都是比较细节的基础知识,比如类方法和实例方法的区别。类的加载,编译后是.class文件还是什么文件。这些问题如果不深究还真的很容易错。

2、编程题

A.去掉字符串中连续的重复字母,只保留一个。

比如aacskjfllkdcc,会变成acskjflkdc

我当时的做法如下:

public static String fun(String s) {

        StringBuilder builder = new StringBuilder(s.charAt(0));

        char index = s.charAt(0);//指针

        int num = 0;

        for (int i = 1; i < s.length(); i++) {

            if (index == s.charAt(i)) {

                num++;//遇到相同字符做标记,num++

            } else {

                //突然遇上不同字符了

                if (num > 0) {//如果此时num大于0说明前面是碰上了相同字符的

                    builder.append(index);//所以只加上指针指向的字符

                    num = 0;//初始化

                    index = s.charAt(i);//指向另一个字符

                    i--;//回退一位

                } else {//没碰上相同字符

                    builder.append(s.charAt(i));//直接加上

                    index = s.charAt(i);//指针变换指向

                }

            }

        }

        builder.append(index);//把最后一位加上

        return builder.toString();

    }

 

B.快速排序

    public static void sort(int[] a, int left, int right) {

        if (left > right)//索引左》右遍历结束

            return;

        int pivot = a[left];//选择最左边作为参照

        int i = left;

        int j = right;

        while (i < j) {

            while (a[j] >= pivot && i < j) {

                j--;//右边大于参照往左移

            }

            while (a[i] <= pivot && i < j) {

                i++;//左边大于参照往右移

            }

 

            if (i < j) {//其它的调换位置,达到比参照小的在左边,比参照大的在右边

                int t = a[i];

                a[i] = a[j];

                a[j] = t;

            }

        }

        //把参照放在左跟右的中间

        a[left] = a[i];

        a[i] = pivot;

        sort(a, left, i - 1);//以上方式遍历左边

        sort(a, i + 1, right);//以上方式遍历右边

    }

C.二分查找

二分查找是建立在已经排序好的数组上的。

直接挑最中间的数出来比较,相等则直接返回,大了说明右边都是比要查找的大,所以去左边找,小了说明左边所有的都小。接着就是递归左边或右边了。

 

D.选择排序

  选择排序是每遍历一次就选最小的跟指针位置交换。就比如56139,初始指针 对着5,在后面发现1最小,然后跟指针交换位置,变成16539;接着指针移到6,然后发现后面3是最小的,跟指针交换位置变成13569。。。。。。

 

E.冒泡排序

  冒泡跟选择排序很像。还是拿56139,首先指针指着5,发现56,顺序是对的,接着看61,发现不对,调换变成51639;再看63,顺序不对调换变成51369;这时候最大的数9已经冒泡到最后了,所以接着比较51,顺序不对,调换15639;比较56,对了,比较63,顺序不对15369,这时候不用比较69了,因为上一轮已经知道9是最大的了,这一轮6是最大的。第三轮,15,不变;53,大了13569;下一轮。。。。

 

F.选择排序和冒泡区别

   选择排序是每遍历一轮就把其中的老大认出来,直接放到最后面;冒泡排序是从头开始选择老大,每次都要pk(交换),舞林大会,胜者为王。

 

G.分割字符串

   传入一个字符串和分隔符,将其分割成字符串数组。

   比如aa_h_o,会被分割成[“aa”,”h”,”o”]

public String[] split(String regex, int limit) {

        /* fastpath if the regex is a

         (1)one-char String and this character is not one of the

            RegEx's meta characters ".$|()[{^?*+\\", or

         (2)two-char String and the first char is the backslash and

            the second is not the ascii digit or ascii letter.

         */

        char ch = 0;

        if (((regex.value.length == 1 &&

             ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||

             (regex.length() == 2 &&

              regex.charAt(0) == '\\' &&

              (((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&

              ((ch-'a')|('z'-ch)) < 0 &&

              ((ch-'A')|('Z'-ch)) < 0)) &&

            (ch < Character.MIN_HIGH_SURROGATE ||

             ch > Character.MAX_LOW_SURROGATE))

        {

            int off = 0;

            int next = 0;

            boolean limited = limit > 0;

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

            while ((next = indexOf(ch, off)) != -1) {

                if (!limited || list.size() < limit - 1) {

                    list.add(substring(off, next));

                    off = next + 1;

                } else {    // last one

                    //assert (list.size() == limit - 1);

                    list.add(substring(off, value.length));

                    off = value.length;

                    break;

                }

            }

            // If no match was found, return this

            if (off == 0)

                return new String[]{this};

 

            // Add remaining segment

            if (!limited || list.size() < limit)

                list.add(substring(off, value.length));

 

            // Construct result

            int resultSize = list.size();

            if (limit == 0) {

                while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {

                    resultSize--;

                }

            }

            String[] result = new String[resultSize];

            return list.subList(0, resultSize).toArray(result);

        }

        return Pattern.compile(regex).split(this, limit);

}

 

Pattern.compile(regex).split(this, limit)方法如下:

    public String[] split(CharSequence input, int limit) {

        int index = 0;

        boolean matchLimited = limit > 0;

        ArrayList<String> matchList = new ArrayList<>();

        Matcher m = matcher(input);

 

        // Add segments before each match found

        while(m.find()) {

            if (!matchLimited || matchList.size() < limit - 1) {

                if (index == 0 && index == m.start() && m.start() == m.end()) {

                    // no empty leading substring included for zero-width match

                    // at the beginning of the input char sequence.

                    continue;

                }

                String match = input.subSequence(index, m.start()).toString();

                matchList.add(match);

                index = m.end();

            } else if (matchList.size() == limit - 1) { // last one

                String match = input.subSequence(index,

                                                 input.length()).toString();

                matchList.add(match);

                index = m.end();

            }

        }

 

        // If no match was found, return this

        if (index == 0)

            return new String[] {input.toString()};

 

        // Add remaining segment

        if (!matchLimited || matchList.size() < limit)

            matchList.add(input.subSequence(index, input.length()).toString());

 

        // Construct result

        int resultSize = matchList.size();

        if (limit == 0)

            while (resultSize > 0 && matchList.get(resultSize-1).equals(""))

                resultSize--;

        String[] result = new String[resultSize];

        return matchList.subList(0, resultSize).toArray(result);

    }

 

 

以上是String源码。

我当时的做法是:

挨个遍历,如果匹配上分隔符(不一定只有一个字符),就将前半部分存入list,最后转成数组。

public static String[] split(String s, String split) {

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

        if (s==null||split == null || split.length() == 0 || split.length() > s.length()) {

            // 分隔符为空

            return new String[] { s };

        }

        int len = s.length();

        char index = 0;//当前的头一个字符

        int last = 0;//上一次的指向(从这里开始截取)

        for (int i = 0; i < s.length(); i++) {

            index = s.charAt(i);

            if (index == split.charAt(0) && (len - i) >= split.length()) {

                boolean isSplit = true;//标志位

                // 一旦检测到两者头字符相同,立马判断接下来的是否都想同

                int k = i;

                for (int j = 0; j < split.length(); j++) {

                    if (s.charAt(k++) != split.charAt(j)) {

                        isSplit = false;//不匹配直接退出循环

                        break;

                    }

                }

                if (isSplit) {

                    //全部匹配

                    list.add(s.substring(last, i));//加入list

                    last = i + split.length();//变换指针

                }

            }

        }

        list.add(s.substring(last));//记得加上,否则漏掉最后一项

        return list.toArray(new String[list.size()]);

    }

 

F.还有一个递归题,题目忘了,用了循环和递归两种方式实现。

 

 

 

三、数据库

主要考察多表查询。广州给人的感觉就是数据库要求比较高。

参考另一篇文章。

 

四、数据库优化

 

老生常谈的话题了。

这次面试最深刻的问题就是,有一个字段status,只有0,1,2三个值,是否需要建立索引?如果数据量达到千万级呢?

当时记得这样是不需要建立索引的,但是最后问面试官时,他说当达到千万级别,并且0的值占80%,这样建立索引是值得的。

  1. 在查询字段上建索引
  2. 尽量不使用不等于查询、判断是否为NULL查询,因为会造成全表查询
  3. 尽量在整型上建索引
  4. 只查询一条数据用limit 1
  5. 可以使用insertTime当作下一次查询的条件
  6. 分页查询使用limit a,b 时,如果a过大会导致查询缓慢,可以使用自增id代替分页。
  7. 索引为char时只会匹配开头,所以索引字段查询时使用%key是不会使用索引查询的。
  8. 先group by 再排序
  9. Union 多表时可以使用多线程分别查询再合起来
  10. 使用exists代替in
  11. 将or 改成 union
  12. 连续的使用between代替in
  13. 不在sql中使用参数
  14. Where中不使用表达式操作,计算
  15. Where中不使用函数操作使用联合索引必须使用第一个索引,并且其它索引顺序同如果只更改一两个字段不要全部字段都改
  16. 大表分页再join
  17. 不使用count(*)
  18. 索引不要太多,
  19. 不要返回用不到的字段
  20. 避免频繁创建和删除临时表
  21. 避免大事务操作
  22. 避免一次返回大数据量
  23. 尽量少排序
  24. 使用union all 代替union
  25. 不使用not in,使用left join代替
  26. 磁盘速度越快越好
  27. 使用group by 代替distinct
  28. 使用use index
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值