BAT实习内推笔试卷(第一场)——个人答案以及分析

第一题:

给定一个长度不小于2的数组arr。 写一个函数调整arr,使arr中要么所有的偶数位上都是偶数,要么所有的奇数位上都是奇数上。 要求:如果数组长度为N,时间复杂度请达到O(N),额外空间复杂度请达到O(1),下标0,2,4,6...算作偶数位,下标1,3,5,7...算作奇数位,例如[1,2,3,4]调整为[2,1,4,3]即可

分析:

时间复杂度请达到O(N),就不能用多重循环,额外空间复杂度请达到O(1),,也就不能用辅助的数组之类的,就是要在单次扫描中,通过交换2个数的位置来实现。

其实我们换个思维来想,如果有2个相同长度数组A,B,满足要么A数组全是偶数,要么B数组全是奇数,是不是就能很快的有思路了,想一下再看下面分析。

2个指针P_A和P_B分别指向A,B,首先P_A找出第一个奇数,然后P_B找出第一个偶数,交换,然后循环这样的方法,直到某个指针达到数组的末尾。

其实这个题和上面的思路一样,相当于把2个数组交叉放在一起,偶数位置的相当于A数组,奇数位置相当于B数组,只是每次移动2个位置

代码:

public class Solution {
    /**
     *  奇数位上都是奇数或者偶数位上都是偶数
     *  输入:数组arr,长度大于2
     *  将arr调整成奇数位上都是奇数或者偶数位上都是偶数
     */
        public void oddInOddEvenInEven(int[] arr) {
        int len = arr.length;
        if (len <= 2) {
            return;
        }
        int even = 0;
        int odd = 1;
        while (even < len && odd < len) {
            if (arr[even] % 2 != 0)
            {
                odd = findEven(arr, odd);
                if (odd < len) {
                    int temp = arr[odd];
                    arr[odd] = arr[even];
                    arr[even] = temp;

                }
            }
            even += 2;
        }

    }

    private int findEven(int[] arr, int odd) {
        for (int i = odd; i < arr.length; i+=2) {
            if (arr[i] % 2 == 0) {
                return i;
            }
        }
        return arr.length;
    }
}

第二题 

给定一个全是正数的数组arr,定义一下arr的最小不可组成和的概念:
1,arr的所有非空子集中,把每个子集内的所有元素加起来会出现很多的值,其中最小的记为min,最大的记为max; 2,在区间[min,max]上,如果有一些正数不可以被arr某一个子集相加得到,那么这些正数中最小的那个,就是arr的最小不可组成和; 3,在区间[min,max]上,如果所有的数都可以被arr的某一个子集相加得到,那么max+1是arr的最小不可组成和; 举例: arr = {3,2,5} arr的min为2,max为10,在区间[2,10]上,4是不能被任何一个子集相加得到的值中最小的,所以4是arr的最小不可组成和;
arr = {3,2,4} arr的min为2,max为9,在区间[2,9]上,8是不能被任何一个子集相加得到的值中最小的,所以8是arr的最小不可组成和; arr = {3,1,2} arr的min为1,max为6,在区间[2,6]上,任何数都可以被某一个子集相加得到,所以7是arr的最小不可组成和; 请写函数返回arr的最小不可组成和。

分析:

我个人的思路是这样

如果只有一个元素,那么肯定是arr[0]+1

如果有2个元素,假设a1<=a2  如果a1+1=a2 那么肯定是a2+1, 否则肯定是a1+1

3个元素以上,假设排序后的顺序为 a1<=a2<=a3<=a4...<=ai,先取前面2个元素a1和a2,a1和a2能组合成的所有情况,就可以利用一个辅助集S合记录,首先集合里面只有3个元素(a1,a2,a1+a2),
然后考虑第3个元素a3,那么a1,a2,a3,a4能组合的所有情况是什么呢:

a1

a2

a3

a1+a2

a1+a3

a2+a3

a1+a2+a3

其实可以看出规律,与辅助集合S中的元素相比,多了的a3,a1+a3,a2+a3,a1+a2+a3,除了a3,其他是不是就是原有集合S中的元素分别与s3相加呢?

原理是这样,辅助集合S的作用就是保存前面所有可能出现的,通过相加能得到数,这样再与新的元素分别相加,就能得到当前所有的组合。

要找出最小的,不用找出所有的不可组成和,当我们新加入一个元素ai的时候,只用判断a1到ai之间的数,是不是都在辅助集合S中,第一次不可组成和,就是最小不可组成和,因为,ai之后的元素都不会比ai小。

import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
public class Solution {
    /**
     *  正数数组中的最小不可组成和
     *  输入:正数数组arr
     *  返回:正数数组中的最小不可组成和
     */
    public int getFirstUnFormedNum(int[] arr) {
        int len=arr.length;
        if(len==0){
            return 0;
        }
        if(len==1){
            return arr[0]+1;
        }
        Arrays.sort(arr);
        if(len==2){
            return arr[1]-arr[0]==1?arr[1]+1:arr[0]+1;
        }

        int min=arr[0];
        int max=arr[len-1];
        int sum=0;
        for(int i=0;i<arr.length;i++){
            sum+=arr[i];
        }
        int[] flag=new int[sum-min+1];

        Set<Integer> integers=new HashSet<Integer>();
        integers.add(arr[0]);
        integers.add(arr[1]);
        integers.add(arr[1]+arr[0]);

        int set_max=arr[1]+arr[0];
        setFlag(arr[0],min,flag);
        setFlag(arr[1],min,flag);
        setFlag(set_max,min,flag);
        for(int i=2;i<len;i++){
            int temp=arr[i];
            Set<Integer> temp_set=new HashSet<Integer>(integers);
            temp_set.add(temp);
            setFlag(temp,min,flag);

            for (Iterator iterator = integers.iterator(); iterator.hasNext();) {
                int v = (Integer) iterator.next();
                temp_set.add(v+temp);
                setFlag(v+temp,min,flag);
            }
            set_max+=temp;
            integers=temp_set;
            int res=judge(flag,temp-min);
            if(res!=-1){
                return res+min;
            }
        }
        int res=judge(flag,sum-min);
        if(res!=-1){
            return res+min;
        }
        return sum+1;
    }

    private int judge(int[] flag, int max) {
        for(int i=0;i<max;i++){
            if(flag[i]==0){
                return i;
            }
        }
        return -1;
    }

    private void setFlag(int i, int min, int[] flag) {
        flag[i-min]=1;
    }
}

第三题

面值为正数的硬币放置成一排,玩家1和玩家2轮流拿走硬币,规定每个玩家在拿硬币时,只能拿走最左或最右的硬币。
例如: 硬币面值与排列为:1,2,3,4,5,现在轮到玩家1拿硬币。 在当前状态下,玩家1只能拿走1或5, 如果玩家1拿走1,则排列变为2,3,4,5,那么接下来玩家2可以拿走2或5,然后继续轮到玩家1拿硬币... 如果玩家1拿走5,则排列变为1,2,3,4,那么接下来玩家2可以拿走1或4;然后继续轮到玩家1拿硬币... 游戏按照这个规则进行,直到所有的硬币被拿完,每个玩家获得的分数是各自拿走硬币的总和。 游戏胜负的规定: 如果玩家1最后获得的分数大于玩家2,则玩家1获胜; 如果玩家2最后获得的分数大于玩家1,则玩家2获胜;
因为玩家1先拿硬币,所以如果最后两人获得分数一样则玩家2获胜; 给定一个数组arr,表示硬币的面值和排列状况,请返回最终获胜者的分数。 例子: arr=[8,7,5,3] 玩家1将获胜,分数为13 所以返回13 arr=[1,9,1] 玩家2将获胜,分数为9 所以返回9

分析,其实就是从动态规划,用一个动态数组d,d[i][j]=max(arr[i]-d[i+1][j],arr[j]-d[i][j-1])
i<j

其实d[i][j]就是表示,如果先取的人,会比后取的人,多多少分?负值表示少多少分。

那么每次比较取左边和取右边,找出最优的

至于return那个公式,其实是这样来的,x+y=sum ,x-y=d    -->   x=(sum+d)/2

public class Solution {
    /**
     *  得到硬币博弈问题的获胜分值
     *  输入:代表硬币排列情况的数组arr
     *  返回:硬币博弈问题的获胜分值
     */
    public int getWinValue(int[] arr) {
        int len=arr.length;
        int[][] d=new int[len][len];
        int sum=0;
        for(int i=0;i<len;i++){
            d[i][i]=arr[i];
            sum+=arr[i];
        }
        for(int w=1;w<len;w++){
            for(int i=0;i<len-w;i++) {
                rule(arr,i,i+w,d);
            }
        }
        return (Math.abs(d[0][len-1])+sum)/2;

    }

    private void rule(int[] arr, int i, int w, int[][] d) {

            int left=arr[i]-d[i+1][w];
            int right=arr[w]-d[i][w-1];
            if(left>right){
                d[i][w]=left;
            }else{
                d[i][w]=right;
            }

    }
}

时间: 2024-10-19 02:04:19

BAT实习内推笔试卷(第一场)——个人答案以及分析的相关文章

2015阿里实习内推一轮被拒

三月初,抱着试试看的心态投了阿里内推的算法工程师.too young too naive.实际应该投的是研发工程师,当时没看清. 问的问题大致涉及: 1.C/C++基础知识深入:指针与引用,const用法,static用法. 2.操作系统:进程与线程,进程间通信,内存管理的堆栈用法. 3.计算机网络:UDP... 4.设计模式:... 5.算法:总结各种排序算法的时间复杂度.(只问了这个......) 6.项目:hadoop的基本原理和框架,wordcount程序的工作机制. ...... 面的

2016届 360校招内推笔试题--2015.8.11

一.填空题40题,时间80分钟 和360实习的题目有一些是重复的.可以参考牛客网:http://www.nowcoder.com/. 二.两道编程题,时间70分钟,题目不是特别难,如下所示 第一道: 思路: 统计每个字符出现的次数.然后遍历一次,找到第一个出现次数为1的字符.在我的vs上调试可以通过,但是到360里面的编辑器就不行了,说是超时.从题目的hint里可以看出可能是从终端接收数据出问题.本想一个一个字符接收的,最后时间不够了.还没解决.下面贴出没有通过的代码. 代码: #include

2016网易有道内推笔试题

1. 洗牌 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description:洗牌在生活中十分常见,现在需要写一个程序模拟洗牌的过程. 现在需要洗2n张牌,从上到下依次是第1张,第2张,第3张一直到第2n张.首先,我们把这2n张牌分成两堆, 左手拿着第1张到第n张(上半堆),右手拿着第n+1张到第2n张(下半堆).接着就开始洗牌的过程,先放下右手的 最后一张牌,

2016 网易校招内推C/C++第二场8.6

选择题20个,每个1.5,编程题3个,每个20,简答题1个10分. 解: 第二题,一开始喵了一眼,好开心,这不是水题么,第一反应想到的是递归,然后马上就写了,结果case10%,一脸蒙蔽,数据值很大,考虑边界条件也比较困难. 递归: 1 #include "iostream" 2 #define MAX 100000 3 #define tag 1000000007 4 5 typedef long long LL; 6 7 using namespace std; 8 9 LL x;

阿里前端内推笔试题

利用面向对象思想完成买家信息删除功能,每一条信息包含: 姓名(name) 性别(sex) 电话号码(number) 省份(province) 实现以下要求: 不能借用任何第三方库,需要使用原生代码实现. 结合给出的基本代码结构,在下方2处code here补充代码,完成买家信息的删除功能,注意此页面要在手机上清晰显示. js代码可以任意调整,例如和使用es6代码完成. <!DOCTYPE html> <html> <head> <meta charset=&quo

2016网易内推笔试题

转载注明出处:勿在浮沙筑高台http://blog.csdn.net/luoshixian099/article/details/52102841 本人笔试的计算机视觉方向,编程题和其他研发岗位类似. 欢迎小伙伴们一起讨论出正确答案. 共20个选择题,3个编程题,1个简答题 一.选择题 1.Linux中,提供TCP/IP包过滤功能的软件叫什么? A.iptables    B.route    C.rarp    D.filter 2.设一组初始关键字序列为{31,65,82,7613,27,1

网易2017内推笔试题 合唱团

题目链接:https://www.nowcoder.com/questionTerminal/661c49118ca241909add3a11c96408c8 题目大意: 略 分析: TODO 代码如下: 原文地址:https://www.cnblogs.com/zaq19970105/p/10793259.html

【北京/上海/南京】【部门直推】【可查询】【实习&amp;社招】字节跳动数据平台前端内推

重要信息,写在前面  [投递邮箱][email protected] [微信扫码] 2019接近尾声,最后上车的机会,一定要抓住!!! 投过字节跳动,面试挂过不要紧!部门直推,捞起再面! 实习同学对项目经验没有强制要求.聪明.基础过硬.对操作系统.计算机网络.数据结构.算法有一定的理解即可! 21届及以后的同学欢迎来实习,实习转正so easy,妈妈再也不用担心我的offer! 我们是干啥的         数据平台为大数据的全生命周期提供服务,覆盖数据产生,传输,建模,统计分析,实验评估,可视

2019年终总结:10场演讲、内推20人、公众号2万粉丝、Code Runner 1000万下载

2019年是值得记录的一年,成长许多,也收获许多. 做了 10 场大会的技术演讲,成功内推 20 人拿到微软 Offer,知乎 Live 2000 听众,公众号 2 万粉丝,GitHub 2万 star,Code Runner 突破 1000 万下载量,成立了 VS Code 中文社区. 10 场演讲 2018 年,只有在 Microsoft Tech Summit 上做过一场大型的公开演讲.而 2019 年却一发不可收拾,不算公司内部的演讲,公开的演讲已经有 10 场了. CodeLab @