玩转大数据大数据算法与实战

快手校招真题一

2020-05-16  本文已影响0人  Tim在路上

快手 获得最多的奖金

题目描述
小明在越南旅游,参加了当地的娱乐活动。小明运气很好,拿到了大奖, 到了最后的拿奖金环节。小明发现桌子上放着一列红包,每个红包上写着奖金数额。
现在主持人给要求小明在这一列红包之间“切”2刀,将这一列红包“切”成3组,并且第一组的奖金之和等于最后一组奖金和(允许任意一组的红包集合是空)。最终第一组红包的奖金之和就是小明能拿到的总奖金。小明想知道最多能拿到的奖金是多少,你能帮他算算吗。

举例解释:桌子上放了红包 1, 2, 3, 4, 7, 10。小明在“4,7”之间、“7,10” 之间各切一刀,将红包分成3组 [1, 2, 3, 4] [7] [10],其中第一组奖金之和=第三组奖金之和=10,所以小明可以拿到10越南盾。
输入描述:
第一行包含一个正整数n,(1<=n<= 200 000),表示有多少个红包。

第二行包含n个正整数d[i],表示每个红包包含的奖金数额。其中1<= d[i] <= 1000 000 000

5
1 3 1 1 4

5

思路是先将红包求出 sum数组,依次求和,sum[i] = sum[n] - sum[j]

如果直接暴力O(n) 查找的话,时间超出,所以改为二分查找, 这里的二分一定要查出相等的值

其次,注意每一个红包 最大可以 1000 000 000 ,所有红包之和可能超出整数范围,所以采用long进行存储


import java.util.*;

public class Main {

    // 思路先求缓存和,然后 sum[i] = sum[n] - sum[k] ,使用 max来保存最大值
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int[] nums = new int[n];
        long[] sums = new long[n+1];
        for(int i=0;i<n;i++){
            nums[i] = in.nextInt();
            sums[i+1] = sums[i] + nums[i];
        }
        long max = 0;
        for(int i=1;i<n;i++){
            /// 这里可以改为二分查找
            long ans = sums[n] - sums[i];
            int left = 0,right = i;
            while (left <= right){
                int mid = left + (right - left)/2;
                if(sums[mid] == ans){
                    max = Math.max(max,ans);
                    break;
                }else if(sums[mid] < ans){
                    left = mid + 1;
                }else{
                    right = mid - 1;
                }
            }
        }
        System.out.println(max);
    }

}

快手 将满二叉树转换为求和树

给满出二叉树,编写算法将其转化为求和树

什么是求和树:二叉树的求和树, 是一颗同样结构的二叉树,其树中的每个节点将包含原始树中的左子树和右子树的和。

二叉树:
10
/
-2 6
/ \ / \
8 -4 7 5

求和树:
20(4-2+12+6)
/
4(8-4) 12(7+5)
/ \ / \
0 0 0 0

二叉树给出前序和中序输入,求和树要求中序输出;
所有处理数据不会大于int;

输入描述:
2行整数,第1行表示二叉树的前序遍历,第2行表示二叉树的中序遍历,以空格分割
输出描述:
1行整数,表示求和树的中序遍历,以空格分割

10 -2 8 -4 6 7 5
8 -2 -4 10 7 6 5

0 4 0 20 0 12 0

思路很简单就是代码比较多,但是题还是比较常规

首先通过先序和中序创建二叉树

然后通过后序在原树上求和

最后中序遍历输出




import java.util.*;

public class Main {

    // 思路先通过前序遍历 和 中序遍历 创建二叉树,然后进行后序遍历

    static class TreeNode{
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int val){
            this.val = val;
        }
    }

    static List<Integer> res = new ArrayList<>();
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String[] preOrder = in.nextLine().split(" ");
        String[] inOrder = in.nextLine().split(" ");
        int[] preArray = new int[preOrder.length];
        int[] inArray = new int[preOrder.length];
        for (int i=0;i<preArray.length;i++){
            preArray[i] = Integer.parseInt(preOrder[i]);
        }
        for (int i=0;i<preArray.length;i++){
            inArray[i] = Integer.parseInt(inOrder[i]);
        }
        // 完成树的建立
        TreeNode root = rebuildTree(preArray, inArray, 0, preArray.length - 1, 0, inArray.length - 1);
        sumTree(root);
        inOrder(root);
        for (int i=0;i<res.size();i++){
            if(i == res.size()-1){
                System.out.print(res.get(i));
            }else{
                System.out.print(res.get(i) + " ");
            }
        }
    }

    private static void inOrder(TreeNode root) {
        if (root == null){
            return;
        }
        inOrder(root.left);
        res.add(root.val);
        inOrder(root.right);
    }

    private static int sumTree(TreeNode root) {
        if(root == null){
            return 0;
        }
        int left = sumTree(root.left);
        int right = sumTree(root.right);
        int res = root.val;
        int lval = root.left == null?0:root.left.val;
        int rval = root.right == null?0:root.right.val;
        root.val = left + right + lval + rval;
        return res;
    }

    private static TreeNode rebuildTree(int[] preArray, int[] inArray, int l1, int r1,int l2,int r2) {
        if(r1 < l1 || r2 <l2){
            return null;
        }
        int val = preArray[l1];
        TreeNode root = new TreeNode(val);
        int index = getIndex(inArray,val,l2,r2);
        int leftLen = index - l2;
        root.left = rebuildTree(preArray,inArray,l1+1,l1+leftLen,l2,index-1);
        root.right = rebuildTree(preArray,inArray,l1+leftLen+1,r1,index+1,r2);
        return root;
    }

    private static int getIndex(int[] inArray, int val, int l2, int r2) {
        for (int i=l2;i<=r2;i++){
            if (val == inArray[i]){
                return i;
            }
        }
        return -1;
    }


}


本题当然可以另一个解法,就是满二叉树的话,只需中序遍历就可以确定整颗树

满二叉树是奇数个,中间节点就是树的根节点,所以不用创建树,直接操作数组即可


import java.util.*;
 
public class Main{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        sc.nextLine();//满二叉树应该只需要中序遍历就可以确定唯一的树,所以不保存第一行输入
        String zhong = sc.nextLine();
        String[] split = zhong.split(" ");
        int[] a = new int[split.length];//中序遍历保存到数组a中
        for(int i=0;i<a.length;i++) {
            a[i] = Integer.parseInt(split[i]);
        }
        int[] ans = new int[a.length];//保存中序遍历的输出结果
        fun(a,0,a.length-1,ans);
        for(int i:ans){
            System.out.print(i+" ");
        }
        sc.close();
    }
 
    private static int fun(int[] a,int left,int right,int[] ans) {
        int mid = (right+left)/2;//中间元素不参与这一轮的计算
        if(right-left==2) {//出口条件
            ans[mid] = a[right] + a[left];
            ans[left] = 0;
            ans[right] = 0;
            return a[mid]+ans[mid];
        }else {
            ans[mid] = fun(a,left,mid-1,ans) + fun(a,mid+1,right,ans);
            return a[mid]+ans[mid];
        }
         
    }
     
}

搭积木

小明有一袋子长方形的积木,如果一个积木A的长和宽都不大于另外一个积木B的长和宽,则积木A可以搭在积木B的上面。好奇的小明特别想知道这一袋子积木最多可以搭多少层,你能帮他想想办法吗?
定义每一个长方形的长L和宽W都为正整数,并且1 <= W <= L <= INT_MAX, 袋子里面长方形的个数为N, 并且 1 <= N <= 1000000.
假如袋子里共有5个积木分别为 (2, 2), (2, 4), (3, 3), (2, 5), (4, 5), 则不难判断这些积木最多可以搭成4层, 因为(2, 2) < (2, 4) < (2, 5) < (4, 5)。
输入描述:
第一行为积木的总个数 N

之后一共有N行,分别对应于每一个积木的宽W和长L
输出描述:
输出总共可以搭的层数

5
2 2
2 4
3 3
2 5
4 5

4

思路是最长递增子序列的解法,使用动态规划解法,时间复杂度太高,采用二分查找进行插入的解法,这题只是把最长递增子序列改为了二维,所以我们在插入时只插入其的索引数组




import java.util.*;

public class Main {

    // 思路是先排序,然后解法依然类似与找零钱的dp,来进行求最大值

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        List<int[]> list = new ArrayList<>();
        for(int i=0;i<n;i++){
            list.add(new int[]{in.nextInt(),in.nextInt()});
        }
        Collections.sort(list, new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                if(o1[0] == o2[0]){
                    return o1[1] - o2[1];
                }
                return o1[0] - o2[0];
            }
        });

        int max = 1;
        int[] tmp = new int[n];
        int end = 0;
        // 这里可以使用二分法插入来加快时间复杂度
        for (int i=0;i<n;i++){
           int left = 0,right = end;
           while (left < right){
               int mid = left + (right - left)/2;
               if (list.get(tmp[mid])[0] <= list.get(i)[0] && list.get(tmp[mid])[1] <= list.get(i)[1]){
                   left = mid + 1;
               }else{
                   right = mid;
               }
           }
           if(left == end){
               end = end + 1;
           }
           tmp[left] = i;
        }
        System.out.println(end);
    }



}

魔法深渊

前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。
由于太过兴奋,晚上月神做了一个奇怪的梦,月神梦见自己掉入了一个被施放了魔法的深渊,月神想要爬上此深渊。

已知深渊有N层台阶构成(1 <= N <= 1000),并且每次月神仅可往上爬2的整数次幂个台阶(1、2、4、....),请你编程告诉月神,月神有多少种方法爬出深渊
输入描述:
输入共有M行,(1<=M<=1000)

第一行输入一个数M表示有多少组测试数据,

接着有M行,每一行都输入一个N表示深渊的台阶数
输出描述:
输出可能的爬出深渊的方式

4
1
2
3
4

1
2
3
6

dp 生成1 到最大值 爬出方式的次数


import java.util.*;

public class Main {

    // 思路是先排序,然后解法依然类似与找零钱的dp,来进行求最大值

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        int m = in.nextInt();
        // 动态规划问题
        int max = 0;
        int[] nums = new int[m];
        for (int i=0;i<m;i++){
            nums[i] = in.nextInt();
            max = Math.max(nums[i],max);
        }
        int len = (int)Math.sqrt(max);
        int[] square = new int[len+1];
        for(int i=0;i<=len;i++){
            square[i] = (int) Math.pow(2,i);
        }
        int[] dp = new int[max+1];
        dp[0] = 1;
        for(int i=1;i<=max;i++){
            int count = 0;
            for (int j=0;j<square.length && square[j] <= i;j++){
                count += dp[i-square[j]];
                count = count % 1000_000_003;
            }
            dp[i] = count;
        }
        for (int i=0;i<nums.length;i++){
            System.out.println(dp[nums[i]]);
        }
    }
}
上一篇下一篇

猜你喜欢

热点阅读