BAT实习内推笔试卷(第一场)——个人答案以及分析
Posted zhchoutai
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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; } }
第二题
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最后获得的分数大于玩家1,则玩家2获胜; 由于玩家1先拿硬币。所以假设最后两人获得分数一样则玩家2获胜; 给定一个数组arr。表示硬币的面值和排列状况,请返回终于获胜者的分数。
样例: arr=[8,7,5,3] 玩家1将获胜,分数为13 所以返回13 arr=[1,9,1] 玩家2将获胜,分数为9 所以返回9
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; } } }
以上是关于BAT实习内推笔试卷(第一场)——个人答案以及分析的主要内容,如果未能解决你的问题,请参考以下文章