hackerrank新年混乱代码优化

时间:2016-08-05 20:17:08

标签: python optimization

我正在尝试优化Hackerranks's 'New Year Chaos' problem的解决方案。问题的关键是这样的

  

有一个n个队列,标记为1到n,每个人都可以直接在他们面前贿赂这些人来交换位置并靠近队列的前面(在这种情况下,列表的索引0 /数组)。每个人最多只能贿赂两次(而且他们不能贿赂已经贿赂过他们的人)

     

在所有贿赂发生后,您将得到人民的命令,而您的工作是确定为达到这一点而发生了多少次贿赂。例如,如果你被给予[3,2,1],那么答案将是3次贿赂(第3人被贿赂,第2人被贿赂,第2人被贿赂)。

我的解决方案是,对于每个人,我计算一个标签大于我的左边的人数(他们将不得不贿赂我到他们左边的人)。为了使事情变得复杂(稍微),只有有人贿赂2次以上(即[4,1,2,3] - 人4受贿的人3,然后2,然后1来到前方)。如果是这种情况,只需输出“Too chaotic”

无论如何这里是代码:

# n is the number of people in the list
# q is the order of the people after the bribery has taken place ex. [1, 3, 2, 5, 4]

for I in range(1, n + 1): # for each person I in the list
    index = q.index(I)
    if I - index > 3: # more than two bribes
        bribes = "Too chaotic"
        break
    for j in range(index): # for each number to the left of I, if greater than I, count it as a bribe
        if q[j] > I: 
            bribes = bribes + 1
print bribes

我的问题是代码超时了一些较大的测试用例(你只需要花费很多时间来运行每个测试用例)。如何优化算法以使其不会超时?我应该用另一种语言尝试这个问题吗?

9 个答案:

答案 0 :(得分:2)

您的代码中存在两个问题。

首先,您应该从给定的数组到结尾迭代给定的数组,而不是相反。原因是如果从头开始迭代,则需要在内部循环中迭代整个数组。但是如果你从最后一个元素迭代,你只需要检查每个数字的左边两个数字来计算反转。我认为这就是为什么你的代码在大型测试用例上“超时”的原因。

其次,当你在最后一行打印贿赂时,你应该检查你是否从外环“突然”,或者在i == n完成。否则,它可能会打印出“Too chaotic”以及您已经计算过的一些贿赂。

答案 1 :(得分:2)

您的解决方案的一种优化方法是从q [i]-2(而不是0)开始嵌套循环。由于没有人可以比其原始位置跳动超过2,因此任何高于q [i]的值只能直到索引q [i] -2。

类似:

for(int j = Math.max(0, q[i] - 2); j < i; j++) {
    if(q[j] > q[i]) {
      bribe++;
    }
}

答案 2 :(得分:0)

def minimumBribes(q):
    bribes = 0
    for i in range(len(q)-1,-1,-1):
        if q[i] - (i + 1) > 2:
            print('Too chaotic')
            return
        for j in range(max(0, q[i] - 2),i):
            if q[j] > q[i]:
                bribes+=1
    print(bribes)

答案 3 :(得分:0)

“我的解决方案”更好,因为它没有循环次数少

 [
  {
    "y1": 12812.2936,
    "y2": 17665.7353,
    "y3": 17665.7353,
    "x1": 15316.4846,
    "x2": 15316.4846,
    "x3": 20137.1603
  },
  {
    "y1": 12812.2936,
    "y2": 12812.2936,
    "y3": 17665.7353,
    "x1": 15316.4846,
    "x2": 20137.1603,
    "x3": 20137.1603
  },
  {
    "y1": 26151.1303,
    "y2": 12812.2936,
    "y3": 12812.2936,
    "x1": 853.6957,
    "x2": 853.6957,
    "x3": 9352.5527
  },
  {
    "y1": 26151.1303,
    "y2": 26151.1303,
    "y3": 24752.8575,
    "x1": 853.6957,
    "x2": 2241.3005,
    "x3": 2241.3005
  },
  {
    "y1": 26151.1303,
    "y2": 24752.8575,
    "y3": 12812.2936,
    "x1": 853.6957,
    "x2": 2241.3005,
    "x3": 9352.5527
  },
  {
    "y1": 24752.8575,
    "y2": 24752.8575,
    "y3": 12812.2936,
    "x1": 2241.3005,
    "x2": 9352.5527,
    "x3": 9352.5527
  },
  {
    "y1": 45117.4663,
    "y2": 45117.4663,
    "y3": 49080.3743,
    "x1": 1295.4000,
    "x2": 4089.4000,
    "x3": 4089.4000
  },
  {
    "y1": 45117.4663,
    "y2": 49080.3743,
    "y3": 49080.3743,
    "x1": 1295.4000,
    "x2": 1295.4000,
    "x3": 4089.4000
  },
  {
    "y1": 21158.2000,
    "y2": 28952.8000,
    "y3": 28952.8000,
    "x1": 12830.2000,
    "x2": 12830.2000,
    "x3": 15884.5000
  },
  {
    "y1": 21158.2000,
    "y2": 21158.2000,
    "y3": 28952.8000,
    "x1": 12830.2000,
    "x2": 15884.5000,
    "x3": 15884.5000
  },
  {
    "y1": 57012.5000,
    "y2": 57012.5000,
    "y3": 57774.5000,
    "x1": 15884.5000,
    "x2": 644.5000,
    "x3": 644.5000
  },
  {
    "y1": 57012.5000,
    "y2": 57774.5000,
    "y3": 57774.5000,
    "x1": 15884.5000,
    "x2": 15884.5000,
    "x3": 644.5000
  },
  {
    "y1": 90889.3000,
    "y2": 90889.3000,
    "y3": 102116.1000,
    "x1": 15884.5000,
    "x2": 12830.2000,
    "x3": 12830.2000
  },
  {
    "y1": 90889.3000,
    "y2": 102116.1000,
    "y3": 102116.1000,
    "x1": 15884.5000,
    "x2": 15884.5000,
    "x3": 12830.2000
  },
  {
    "y1": 96747.5000,
    "y2": 99206.7000,
    "y3": 99206.7000,
    "x1": 12830.2000,
    "x2": 12830.2000,
    "x3": 644.5000
  },
  {
    "y1": 96747.5000,
    "y2": 96747.5000,
    "y3": 99206.7000,
    "x1": 12830.2000,
    "x2": 644.5000,
    "x3": 644.5000
  },
  {
    "y1": 76243.7000,
    "y2": 79679.1000,
    "y3": 79679.1000,
    "x1": 2689.2000,
    "x2": 2689.2000,
    "x3": 758.8000
  },
  {
    "y1": 76243.7000,
    "y2": 76243.7000,
    "y3": 79679.1000,
    "x1": 2689.2000,
    "x2": 758.8000,
    "x3": 758.8000
  }]

答案 4 :(得分:0)

最终的优化是在内部循环中,以排除所有从未向当前人行贿的人。

当您到达当前人员的最终职位时,您已经停止了此循环,因为显然没有人落后于他们的最终职位...

但是那些在前面的人呢?通过发出两次贿赂,此人充其量最多只能升至其出发地之前的两个位置。但是在那之前没有人能够贿赂他们,因此我们可以排除所有人。

因此,内部循环范围从我的起始位置前面的两个点到我的最终位置。当列表很长时,哪个会消除很多迭代。

def minimumBribes(q):
    bribes = 0
    for final_pos, start_pos in enumerate(q):
        # Abort if anyone is more than two bribes ahead of where they started
        if  final_pos + 1 < start_pos - 2:
            print('Too chaotic')
            return
        # Count the number of people who started behind me, who are ahead of my
        # final position. Conduct the search between two spots forward of where
        # I started, thru to the person in front of me in the end; as these are
        # the only people to have potentially bribed me.
        potential_bribers = range(max(start_pos - 2, 0), final_pos)
        bribes += [q[briber] > start_pos for briber in potential_bribers].count(True)
    print(bribes)

我也许可以解决这些难题,但我永远都无法在他们的时间表内做到。这就是为什么当上一次潜在雇主在我面前进行黑客等级测试时,我什至不去尝试的原因。他们可以有无赖,其他我们凡人也有stackoverflow。

答案 5 :(得分:0)

只是遇到了这个问题,我花了一些时间,但这是一个不错的干净解决方案,它针对较大的测试用例进行了优化(并在HackerRank上通过10/10)。我意识到与您采用的方法稍有不同,但我想与您分享一下,因为它运行良好,可能仍会有所帮助。

对我有帮助的一个关键点是,对于队列中任何给定的X人,寻找超越他们的人最需要的就是X人开始之前的一个地点。 >。人员可能会被超车2次以上,因此,例如,即使队列长度为1000人,人员1仍可能排在队列的后面。但是,Y人最终不能超过他们开始的位置超过(否则他们必须超越两次以上)。这就是为什么您可以肯定的是,对于超车的人,您不需要在X人物开始的位置前看1个位置(在最近的可能的超者前面2个位置)。

def minimumBribes(q):

    count = 0
    tooChaotic = False

    for i in range(len(q)):

        # to translate between q[i] and the position in a zero-indexed python list, you have to add 1, so here it's i+3 rather than i+2

        if q[i] > i + 3:
            print("Too chaotic")
            tooChaotic = True
            break
        else:

            # q[i]-2 rather than q[i]-1 since python is zero-indexed but the people in the queue start at 1

            start = max(0, q[i]-2)
            for j in range(start, i):
                    if q[j] > q[i]:
                        count += 1

    if tooChaotic == False:
        print(count)

答案 6 :(得分:0)

def minimumBribes(q):
    moves = 0
    for pos, val in enumerate(q):
        if (val-1) - pos > 2:
            return "Too chaotic"
        for j in xrange(max(0,val-2), pos):
            if q[j] > val:
                moves+=1
    return moves

答案 7 :(得分:0)

这是一个完整的 C++ 解决方案,基于@lazywiz 的评论:

void minimumBribes(vector<int> q) {
    int numBribes{0};
    bool chaotic = false;
    vector<bool> visited(100000, false);

    for (int i=0; i<q.size(); i++) {
        int pos = i+1;
        if (q[i] - pos > 2) { 
            chaotic = true; 
            break; 
        } else if (q[i] <= pos) {
            for (int j=q[i]+1; j<=pos+3; j++) {
                if (visited[j-1]) { numBribes++; }
            }
        }
        visited[q[i]-1] = true;
    }
    
    if (chaotic) {
        cout << "Too chaotic\n";
    } else {
        cout << numBribes << "\n";
    }
}

答案 8 :(得分:-2)

def minimumBribes(q):
total_bribe=0
chaos=""
for i in range(0, len(q)):
    if chaos == "Too chaotic":
        break
    bribe_count=0
    for j in range(i, len(q)):
        if q[i]>q[j]:
            if bribe_count<2:
                bribe_count+=1
            else:
               chaos="Too chaotic"
               break

    total_bribe+=bribe_count
if chaos=="":
    print(total_bribe)
else: 
    print(chaos)

我们还能进一步优化此代码吗?