字节跳动2019年春季社招面试内容

来自深圳字节跳动大佬熊熊熊帮忙内推的。
从简历投递到约面试一天,约的第二天面试。
开始,自我介绍,面试官看你的简历,差不多5分钟左右,随便说就行,避免尴尬。
开始刷算法题:

给定两个链表和第三个链表,找规律然后进行算法实现。

其实就是实现加法,有进位,而且需要考虑链表长度不一样的情况。

例子:
List1 : 1 -》 3 -〉5
List2:2 -》4 -〉2
List3:3 -》 7 -〉 7

例子2:
List1:1 -》3 -〉 9
List2:。 2 -》 3
List3:1 -》 6 -〉2

思路:
将两个链表进行翻转,翻转后从头开始进行相加,直到某个链表到了头,相加过程中维护一个进位符号。最后再将相加的结果进行翻转即可。

代码:

package interview;

import leetcode.leetcodeaa.base.ListNode;

public class SumOfArrayList {
    public static void main(String[] args) {
        SumOfArrayList sum = new SumOfArrayList();
        ListNode root = new ListNode(1);
        ListNode node1 = new ListNode(2);
        ListNode node2 = new ListNode(3);
        ListNode node3 = new ListNode(4);
        root.next = node1;
        node1.next = node2;
        node2.next = node3;
        node3.next = null;

        ListNode root2 = new ListNode(8);
        ListNode node4 = new ListNode(5);
        ListNode node5 = new ListNode(6);
        root2.next = node4;
        node4.next = node5;
        node5.next = null;

        sum.printList(root);
        sum.printList(root2);
        ListNode add1 = sum.sumOfArrayList(root2, root);
        sum.printList(add1);
    }

    private ListNode sumOfArrayList(ListNode root1, ListNode root2) {
        ListNode rNode1 = reverseList(root1);
        ListNode rNode2 = reverseList(root2);
        ListNode resNode = sumList(rNode1, rNode2);
        return reverseList(resNode);
    }

    private ListNode reverseList(ListNode root) {
        if (null == root) {
            return null;
        }
        ListNode preNode;
        ListNode curNode;
        ListNode nextNode;
        preNode = root;
        curNode = root.next;
        preNode.next = null;
        while(null != curNode) {
            nextNode = curNode.next;
            curNode.next = preNode;
            preNode = curNode;
            curNode = nextNode;
        }
        return preNode;
    }

    private ListNode sumList(ListNode root1, ListNode root2) {
        int add = 0;
        ListNode res = new ListNode(0);
        ListNode out = res;
        while(root1 != null && root2 != null) {
            ListNode nextNode = new ListNode(0);
            nextNode.val = (root1.val + root2.val + add) % 10;
            add = (root1.val + root2.val) / 10;
            root1 = root1.next;
            root2 = root2.next;
            res.next = nextNode;
            res = nextNode;
        }
        while(root1 != null){
            ListNode nextNode = new ListNode(0);
            nextNode.val = root1.val + add;
            add = 0;
            root1 = root1.next;
            res.next = nextNode;
            res = nextNode;
        }
        while(root2 != null){
            ListNode nextNode = new ListNode(0);
            nextNode.val = root2.val + add;
            add = 0;
            root2 = root2.next;
            res.next = nextNode;
            res = nextNode;
        }
        return out.next;
    }

    private void printList(ListNode root) {
        while (null != root) {
            System.out.print(root.val + " -> ");
            root = root.next;
        }
        System.out.println();
    }
}

非递归实现二叉树中序遍历

这道题从思路上看很简单,就是利用一个栈,先将当前指针指向根结点,当前节点入栈,指针指向当前节点左侧子树,指针为空,指针指向栈弹出元素,打印指针元素值,指针指向当前节点右子树,循环

代码:

package interview;


import java.util.Stack;

public class LDRnonrecursion {
    public void LDR(leetcode.base.TreeNode root) {
        if (null == root)
            return;
        Stack<leetcode.base.TreeNode> stack = new Stack<>();
        while(root!= null || !stack.isEmpty()) {
            while(root != null) {
                stack.push(root);
                root = root.left;
            }
            root = stack.peek();
            stack.pop();
            System.out.println(root.val);
            root = root.right;
        }
    }
}

寻找两个排序数组第K小的数字

这道题一开始是想到通过两个指针分别指向两个数组头部,然后比较每个指针下一位的大小,决定哪个继续向前移动。-这样实现时间复杂度很高
后来想到了其实可以用二分,区分以下的情况:
假设短数组shortArr,长度为lenS;
长数组为longArr,长度为lenL。

  1. 如果k<lenS,那么短数组取k个数,长数组取k个数,这两段数组的上中位数就是整体第k小的数;
  2. 如果k>lenL,对于longArr中前k-lenS-1个数,不能满足,因为即使他们比shortArr中的所有数都大,也无法达到第k个数。longArr中的第k-lenS个数,如果他比shortArr中的所有数都大,那么它就是第k小的数,否则,它也不是。对于shortArr中的前k-lenL-1个数,也是这样的。如果shortArr[k-lenL-1]和longArr[k-lenS-1]都不是第k小的数,那么shortArr[k-lenL … lenS-1]和longArr[k-lenS … lenL-1]的上中位数就是整体第k小的数。(因为前一段长度k-lenL,和k-lenS,中位数长度就是((lenS-(k-lenS) + (lenL - (k-lenL) )/ 2,也就是lenS+lenL-k,和前面的长度相加就等于k
  3. 如果lenS<k<lenL,对于longArr前k-lenS-1个数,都不能满足要求,如果longArr中第k-lenS个数比shortArr中所有数都大,那么longArr[k-lenS]就是第k小的数。否则,对于longArr第k个数以后的数,也无法满足,那么shortArr[0 … lenS-1]和longArr[k-lenS … lenL-1]的上中位数就是所求的值。

也就衍生出了另一道题,求两个相同长度数组的上中位数。
同样使用二分法,取两个数组中间值比较,若中间值相同,则返回这个值,
否则中位数应当在中间值大的那个数组左侧,和中间值小的那个数组右侧。

代码:

package search;

import java.util.Arrays;

public class getKthInTwoSortedArray {
    public static void main(String[] args) {
        int[] arr1 = new int[]{3, 4};
        int[] arr2 = new int[]{5, 6};
        System.out.println(getKth(arr1, arr2,2));
        System.out.println(getKth(arr1, arr2,3));
        int[] arr3 = new int[]{1, 2, 3, 4, 5};
        int[] arr4 = new int[]{4, 8};
        System.out.println(getKth(arr3, arr4,2));
        System.out.println(getKth(arr3, arr4,3));
        System.out.println(getKth(arr3, arr4,6));
    }


    private static int getKth(int[] arr1, int[] arr2, int k) {
        if (null == arr1 || arr1.length == 0) {
            return arr2[k];
        }
        if (null == arr2 || arr2.length == 0) {
            return arr1[k];
        }
        // init
        int[] shortArr;
        int[] longArr;
        if (arr1.length < arr2.length) {
            shortArr = arr1;
            longArr = arr2;
        } else {
            shortArr = arr2;
            longArr = arr1;
        }
        int lenS = shortArr.length;
        int lenL = longArr.length;
        // calc
        if (k <= lenS) {
            return getUpMid.getUpMidValue(Arrays.copyOfRange(shortArr, 0, k), Arrays.copyOfRange(longArr, 0 , k));
        } else if (k > lenL) {
            if (longArr[k - lenS - 1] > shortArr[lenS-1]) {
                return longArr[k - lenS - 1];
            } else if (shortArr[k - lenL - 1] > longArr[lenL-1]) {
                return shortArr[k - lenL - 1];
            } else {
                return getUpMid.getUpMidValue(Arrays.copyOfRange(shortArr, k-lenL, lenS), Arrays.copyOfRange(longArr, k-lenS , lenL));
            }
        } else {
            if (longArr[k - lenS - 1] > shortArr[lenS-1]) {
                return longArr[k - lenS - 1];
            } else {
                return getUpMid.getUpMidValue(Arrays.copyOfRange(shortArr, 0, lenS), Arrays.copyOfRange(longArr, k-lenS , k));
            }
        }
    }
}

子类方法:

package search;

public class getUpMid {
    public static void main(String[] arg) {
        int[] arr1 = new int[]{3, 4};
        int[] arr2 = new int[]{5, 6};
        System.out.print(getUpMidValue(arr1, arr2));
    }


    public static int getUpMidValue (int[] arr1, int[] arr2) {
        int left1 = 0;
        int right1 = arr1.length - 1;
        int left2 = left1;
        int right2 = right1;
        int mid1, mid2;
        while (left1 < right1) {
            mid1 = (left1 + right1) / 2;
            mid2 = (left2 + right2) / 2;
            int offset = (right1 - left1 + 1) & 1 ^ 1;
            if (arr1[mid1] == arr2[mid2]) {
                return arr1[mid1];
            } else if (arr1[mid1] > arr2[mid2]) {
                right1 = mid1;
                left2 = mid2 + offset;
            } else {
                right2 = mid2;
                left1 = mid1 + offset;
            }
        }
        return Math.min(arr1[left1], arr2[left2]);
    }
}

其他基础知识

Mysql,引擎,innoDB和MyIsam区别,索引,id。
Redis,基本数据结构,利用Redis实现分布式锁。

总结

总的来说以算法为主,可惜太紧张了没全答上来,惨烈的跪了,好好准备秋天继续面。平时要多动手多动脑,代码要落实到敲出来才算理解,不然就只是纸上谈兵,一动手就Bug百出。

上一篇:Sqlserver将表中某列数据以符号分成多行


下一篇:LeetCode-171 Excel表列序号