BAT实习内推笔试卷(第一场)

NO.1   给定一个长度不小于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]即可

解答:题目要求是或者只要有一个条件满足即可结束,所以我们采用两个游标分别表示奇数位和偶数位,遇到两个不符合的就交换,直到其中一个条件满足就结束。

class Solution {
public:
    /**
     *  奇数位上都是奇数或者偶数位上都是偶数
     *  输入:数组arr,长度大于2
     *  len:arr的长度
     *  将arr调整成奇数位上都是奇数或者偶数位上都是偶数
     */
    void oddInOddEvenInEven(vector<int>& arr, int len) {
        int i=0,j=1;
        while(i<len&&j<len){
            while((arr[i]&1)==0)i+=2;
            while((arr[j]&1)==1)j+=2;
            if(i<len&&j<len)
            swap(arr[i],arr[j]);
        }
    }
};
NO.2   给定一个全是正数的数组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的最小不可组成和。

解法:使用蛮力法,思路要清晰,循环计算前i个元素组成的数组的和的总个数,并将其值保存到set对象中,然后没增加一个新元素,和集合就在原有的基础上加上一个元素,新的结果要利用临时数组存一下,然后在插入到set中即可。

class Solution {
public:
	/**
	 *	正数数组中的最小不可组成和
	 *	输入:正数数组arr
	 *	返回:正数数组中的最小不可组成和
	 */
	int getFirstUnFormedNum(vector<int> arr, int len) {
        set<int> s;
        vector<int> tmp;        
        for(int i=0;i<arr.size();i++){
            for(set<int>::iterator it=s.begin();it!=s.end();it++)tmp.push_back(*it+arr[i]);
            for(vector<int>::iterator it=tmp.begin();it!=tmp.end();it++)s.insert(*it);
            s.insert(arr[i]);
            tmp.clear();
        }        
        set<int>::iterator it=s.begin();
        int mi=*it;           
        for(it++;it!=s.end();it++){
            if(*it!=mi+1){
                return mi+1;
            }
            mi++;
        }
        return mi+1;
    }
};
NO.3  
面值为正数的硬币放置成一排,玩家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

解法:典型的动态规划题目,dp[i][j]表示从区间i和j之间首先选择硬币得到的最大分数,sum[i][j]表示i到j区间内所有硬币加起来的和,则有以下递推关系式:dp[i][j]=sum[i][j]-min(dp[i+1][j],dp[i][j-1]),因此可以根据这个表达式分别计算,最后从dp[0][len-1]和max(dp[0][len-2],dp[1][len-1])中选择一个更大值即可。

class Solution {
public:
	/**
	 *	得到硬币博弈问题的获胜分值
	 *	输入:代表硬币排列情况的数组arr
	 *	返回:硬币博弈问题的获胜分值
	 */
	int getWinValue(vector<int> arr, int len) {
        if(len==1) return arr[0];
		vector<vector<int>> dp(len,vector<int>(len,0));
        vector<int>sum(arr);
        for(int i=0;i<len;i++){            
            dp[i][i]=arr[i];
            if(i>0)
            sum[i]+=sum[i-1];
        }
        for(int i=1;i<len;i++){
            for(int j=0;j<len-i;j++){                
                dp[j][i+j]=sum[i+j]-(j-1<0?0:sum[j-1])-min(dp[j][i+j-1],dp[j+1][i+j]);
            }
        }        
        return max(dp[0][len-1],min(dp[0][len-2],dp[1][len-1]));
    }
};

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值