当前位置:   article > 正文

BAT实习内推笔试卷(第一场)_给定一个长度不小于2的数组arr,实现一个函数调整arr,要么让所有的偶数下标都是偶

给定一个长度不小于2的数组arr,实现一个函数调整arr,要么让所有的偶数下标都是偶

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]即可

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

  1. class Solution {
  2. public:
  3. /**
  4. * 奇数位上都是奇数或者偶数位上都是偶数
  5. * 输入:数组arr,长度大于2
  6. * len:arr的长度
  7. * 将arr调整成奇数位上都是奇数或者偶数位上都是偶数
  8. */
  9. void oddInOddEvenInEven(vector<int>& arr, int len) {
  10. int i=0,j=1;
  11. while(i<len&&j<len){
  12. while((arr[i]&1)==0)i+=2;
  13. while((arr[j]&1)==1)j+=2;
  14. if(i<len&&j<len)
  15. swap(arr[i],arr[j]);
  16. }
  17. }
  18. };
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中即可。

  1. class Solution {
  2. public:
  3. /**
  4. * 正数数组中的最小不可组成和
  5. * 输入:正数数组arr
  6. * 返回:正数数组中的最小不可组成和
  7. */
  8. int getFirstUnFormedNum(vector<int> arr, int len) {
  9. set<int> s;
  10. vector<int> tmp;
  11. for(int i=0;i<arr.size();i++){
  12. for(set<int>::iterator it=s.begin();it!=s.end();it++)tmp.push_back(*it+arr[i]);
  13. for(vector<int>::iterator it=tmp.begin();it!=tmp.end();it++)s.insert(*it);
  14. s.insert(arr[i]);
  15. tmp.clear();
  16. }
  17. set<int>::iterator it=s.begin();
  18. int mi=*it;
  19. for(it++;it!=s.end();it++){
  20. if(*it!=mi+1){
  21. return mi+1;
  22. }
  23. mi++;
  24. }
  25. return mi+1;
  26. }
  27. };
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])中选择一个更大值即可。

  1. class Solution {
  2. public:
  3. /**
  4. * 得到硬币博弈问题的获胜分值
  5. * 输入:代表硬币排列情况的数组arr
  6. * 返回:硬币博弈问题的获胜分值
  7. */
  8. int getWinValue(vector<int> arr, int len) {
  9. if(len==1) return arr[0];
  10. vector<vector<int>> dp(len,vector<int>(len,0));
  11. vector<int>sum(arr);
  12. for(int i=0;i<len;i++){
  13. dp[i][i]=arr[i];
  14. if(i>0)
  15. sum[i]+=sum[i-1];
  16. }
  17. for(int i=1;i<len;i++){
  18. for(int j=0;j<len-i;j++){
  19. 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]);
  20. }
  21. }
  22. return max(dp[0][len-1],min(dp[0][len-2],dp[1][len-1]));
  23. }
  24. };

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/AllinToyou/article/detail/434371
推荐阅读
相关标签
  

闽ICP备14008679号