面试总结

时间: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
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值