Codility EvenSums Game

时间:2016-04-21 23:43:51

标签: algorithm

我正在努力完成编纂挑战,以提高我的编程技巧。挑战的细节是here
我也会在这里复制问题陈述。

  

甚至总和也是两个玩家的游戏。玩家被给予一系列N.   正整数并交替轮流。每回合,一名球员   选择非空切片(连续元素的子序列)   该切片中的值之和为偶数,然后删除切片   并连接序列的其余部分。第一个球员   无法做出合法举动的人会输掉比赛。

     

你对对手玩这个游戏,你想知道你是否   假设你和你的对手都发挥出最佳状态,我们就能赢。你挪开   第一

     

写一个函数:

     

string solution(vector< int>& A);

     

给定由N个整数组成的零索引数组A,返回a   格式为“X,Y”的字符串,其中X和Y分别是第一个和   您应该删除的切片的最后位置(包括)   假设你有一个获胜策略,首先是为了获胜。如果   有多个这样的获胜片,功能应该返回   X值最小的那个。如果有多个切片   如果X的值最小,则函数应返回最短的值。   如果您没有获胜策略,该功能应返回“NO   解”。

     

例如,给定以下数组:

     

A [0] = 4 A [1] = 5 A [2] = 3 A [3] = 7 A [4] = 2函数   应该返回“1,2”。从位置1到2移除切片后   (偶数和5 + 3 = 8),其余数组为[4,7,2]。   然后对手将能够删除第一个元素(偶数   总和4)或最后一个元素(偶数为2)。之后你可以做一个   移动离开只包含[7]的数组,所以你的对手会   没有合法的举动而且会失败。其中一个可能的游戏显示在上面   如下图:

     

https://codility-frontend-prod.s3.amazonaws.com/media/task_img/even_sums_game/media/auto/tikz242689cc8162bed50db48168cf844337.png

     

请注意,删除切片“2,3”(偶数和3 + 7 = 10)是   也是一个成功的举动,但切片“1,2”的X值较小。

     

对于以下数组:

     

A [0] = 2 A [1] = 5 A [2] = 4该函数应返回“NO   解决方案“,因为没有策略可以保证您获胜。

     

假设:

     

N是[1..100,000]范围内的整数;数组A的每个元素   是[1..1,000,000,000]范围内的整数。复杂度:

     

预期的最坏情况时间复杂度为O(N);预期的最坏情况空间   复杂度是O(N),超出了输入存储(不包括存储   输入参数需要)。输入数组的元素可以是   修改。

首先我对问题陈述的理解不足,为什么在给定的例子中,第一个玩家在第一个移动中不能将4作为偶数范围,因此该函数应该返回0,0而不是1,2。


第二,我对解决问题的想法是计算输入数组中偶数范围的数量,如果计数甚至让玩家获胜,我应该找到玩家可以采用的第一个偶数范围。

但我无法在分配的时间内解决它,也无法再次参加考试。

这是我尝试过的代码:

    string solution(vector<int> &A) {
    int num_even_ranges = 0;
    int sum = 0;
    for (int i = 0; i < A.size(); i++)
    {
        sum += (A[i]%2);
        if (sum % 2 == 0 || A[i]%2 == 0)
        {
            num_even_ranges++;
            sum = 0;
        }
    }
    if (num_even_ranges % 2 == 0)
        return "NO SOLUTION";
    sum = 0;
    int start = 0;
    for (int i = start; i < A.size(); i++)
    {
        sum += A[i];
        if (sum % 2 == 0 && i > start)
        {
            return to_string(start) + "," + to_string(i);
        }

        if (i + 1 < A.size())
        {
            if (A[i] % 2 == 0 && A[i+1] % 2 == 1)
            {
                sum = 0;
                start = i + 1;
            }
        }
    }
}


如果不是这个问题的正确解决方案,我对问题的解决方案是否正确。

3 个答案:

答案 0 :(得分:4)

关于你的第一个问题,如果第一个玩家拿4(0,0),剩下的数组是:5,3,7,2。然后对手可以拿3,7,2并且第一个玩家将会松动,因为剩下的5个是奇数。所以它不是有效的解决方案。

答案 1 :(得分:2)

我在Javascript中获得了解决方案,请参考以下代码

Javascript代码:

function len(obj){
if(obj instanceof Array || typeof obj === "string")
    return obj.length;
else {
    var count = 0;
    for(var i in obj){
        if(obj.hasOwnProperty(i))
        count++;
    }
    return count;
}
}

function check(start, end) {
if (start > end) {
    res = 'NO SOLUTION';
}
else {
    res = start.toString() + ',' + end.toString();
}

return res;
}

function trans(strr){
if (strr =='NO SOLUTION') {
    return [1, -1]
}
else {
   a = strr.split(',');
}

return [parseInt(a[0]), parseInt(a[1])];
}

function solution(A){
odd_list = [];
for(var ind=0; ind<A.length; ind++)
{
    if(A[ind]%2==1) {
        odd_list.push(parseInt(ind));    
    }
}

if (len(odd_list)%2 == 0) {
    return check(0, len(A) - 1);
}

 tempList = odd_list;
 odd_list = [];

 odd_list.push(-1);

 for(var i=0; i< tempList.length; i++) {
     odd_list.push(tempList[i]);
 }

 odd_list.push(len(A));

 var res_cand = [];
 count = odd_list[1];
 second_count = len(A) - 1 - odd_list[odd_list.length-2];
 first_count = odd_list[2]- odd_list[1] - 1;

 if (second_count >= count) {
    res_cand.push(trans(check(odd_list[1] + 1 , len(A) - 1 - count ))); 
 }

 if (first_count >= count) {
    res_cand.push(trans(check(odd_list[1] + count + 1, len(A) - 1))) 
 }

twosum = first_count + second_count;

if (second_count < count && count <= twosum) {
    res_cand.push(trans(check(odd_list[1] + (first_count - (count -     second_count )) + 1, odd_list[odd_list.length-2] )));
}

count = len(A) - 1 - odd_list[odd_list.length-2];
first_count = odd_list[1];
second_count = odd_list[odd_list.length-2] - odd_list[odd_list.length-3] - 1;

if(first_count >= count) {
    res_cand.push(trans(check( count, odd_list[odd_list.length-2] - 1 )));
}

if (second_count >= count) {
    res_cand.push(trans(check( 0, odd_list[odd_list.length-2] - count - 1)))
}

twosum = first_count + second_count;

if(second_count < count && count <= twosum) {
    res_cand.push(trans(check(count-second_count, odd_list[odd_list.length-3])))
}

cur = [-1, -2];

res_cand =  res_cand.sort(sortFunction);

for(var i= res_cand.length-1 ; i >= 0 ; i--) {
      var row = res_cand[i]; 
      if(row[0] !== -1) {
        cur = row;  
      }
}

return check(cur[0], cur[1]);
}

function sortFunction(a, b) {
if (a[0] === b[0]) {
    return 0;
}
else {
    return (a[0] < b[0]) ? -1 : 1;
}
}

您可以在以下小提琴链接中找到答案

https://jsfiddle.net/3ed1kuoj/

答案 2 :(得分:-2)

移动(0,0)有效,因为在每个回合中,玩家只能使用其总和为偶数的子序列进行移动。

  

&#34;在每个回合中,玩家选择一个非空切片(一个子序列)   连续元素)使得该切片中的值之和为   甚至&#34;

注意:每次移动后,我们只考虑剩余序列的操作/移动

After player1's first move(0,0), the remaining sequence will be [5,3,7,2],
then player2's first move(0,1), the remaining sequence will be [7,2],
then player1's second move(1,0), the remaining sequence will be [7]
Now player 2 is unable to make any legal move! So player 1 win's 

因此它是一个成功的战略!