Python算法练习 10.12

leetcode 649 Dota2参议院

Dota2 的世界里有两个阵营:Radiant(天辉)和 Dire(夜魇)

Dota2 参议院由来自两派的参议员组成。现在参议院希望对一个 Dota2 游戏里的改变作出决定。他们以一个基于轮为过程的投票进行。在每一轮中,每一位参议员都可以行使两项权利中的 一 项:

  • 禁止一名参议员的权利:参议员可以让另一位参议员在这一轮和随后的几轮中丧失 所有的权利 
  • 宣布胜利:如果参议员发现有权利投票的参议员都是 同一个阵营的 ,他可以宣布胜利并决定在游戏中的有关变化。

给你一个字符串 senate 代表每个参议员的阵营。字母 'R' 和 'D'分别代表了 Radiant(天辉)和 Dire(夜魇)。然后,如果有 n 个参议员,给定字符串的大小将是 n

以轮为基础的过程从给定顺序的第一个参议员开始到最后一个参议员结束。这一过程将持续到投票结束。所有失去权利的参议员将在过程中被跳过。

假设每一位参议员都足够聪明,会为自己的政党做出最好的策略,你需要预测哪一方最终会宣布胜利并在 Dota2 游戏中决定改变。输出应该是 "Radiant" 或 "Dire" 。

示例 1:

输入:senate = "RD"
输出:"Radiant"
解释:
第 1 轮时,第一个参议员来自 Radiant 阵营,他可以使用第一项权利让第二个参议员失去所有权利。
这一轮中,第二个参议员将会被跳过,因为他的权利被禁止了。
第 2 轮时,第一个参议员可以宣布胜利,因为他是唯一一个有投票权的人

示例 2:

输入:senate = "RDD"
输出:"Dire"
解释:
第 1 轮时,第一个来自 Radiant 阵营的参议员可以使用第一项权利禁止第二个参议员的权利。
这一轮中,第二个来自 Dire 阵营的参议员会将被跳过,因为他的权利被禁止了。
这一轮中,第三个来自 Dire 阵营的参议员可以使用他的第一项权利禁止第一个参议员的权利。
因此在第二轮只剩下第三个参议员拥有投票的权利,于是他可以宣布胜利

 我的思路:

设置一个对应状态数组,有效为1,禁用为2

“最好的策略”就是每次轮到谁投票,如果敌对阵营还有有效投票的参议员,那就禁用,如果没有,就宣布胜利

class Solution(object):
    def predictPartyVictory(self, senate):
        """
        :type senate: str
        :rtype: str
        """
        state = [1] * len(senate)  # 每个参议员的状态 1正常 2被禁用
        def circle():  # 一轮投票过程
            count = 0
            while count < len(senate):
                if state[count] != 2:
                    if senate[count] == 'R':
                        j = 0
                        while j < len(senate) :
                            if senate[j] == 'D' and state[j] == 1:
                                state[j] = 2
                                break
                            j += 1
                    if senate[count] == 'D':
                        j = 0
                        while j < len(senate):
                            if senate[j] == 'R' and state[j] == 1:
                                state[j] = 2
                                break
                            j += 1
                # print(count, state)
                count += 1

        while 1:
            circle()
            first = ''
            end = ''
            count1, count2 = 0, 0
            while count1 < len(senate):
                if state[count1] != 2:
                    first = senate[count1]
                    break
                count1 += 1
            while count2 < len(senate):
                if state[count2] != 2:
                    end = senate[count2]
                if first != end and end:
                    break
                count2 += 1
            # print(state, first, end)
            # print(state)
            if first == end:
                if first == 'D':
                    return "Dire"
                else:
                    return "Radiant"

呜呜,没想到思路错了:

 看了题解,原来不是从头开始选择敌对阵营的参议员,而是选择【最早有机会投票】的敌对阵营参议员,也就是接下来离我最近的敌对阵营参议员,如果挑选了其他较晚投票的议员,那么等到最早可以进行投票的那一名议员行使权利时,一名天辉方议员就会丧失权利,这样就得不偿失了。

修改之后思路正确但超时:

class Solution(object):
    
    def predictPartyVictory(self, senate):
        state = [1] * len(senate)  # 每个参议员的状态 1正常 2被禁用
        # queue = deque()

        def circle():  # 一轮投票过程
            count = 0
            while count < len(senate):
                if state[count] != 2:
                    if senate[count] == 'R':
                        j = count
                        flag = 1
                        while j < len(senate) :
                            if senate[j] == 'D' and state[j] == 1:
                                state[j] = 2
                                flag = 2 # 已经投过票了
                                break
                            j += 1
                        if flag == 1:
                            j = 0
                            # 检查我前面的敌对参议员
                            while j < count:
                                if senate[j] == 'D' and state[j] == 1:
                                    state[j] = 2
                                    flag = 2
                                    break
                                j += 1
                    if senate[count] == 'D':
                        j = count
                        flag = 1
                        while j < len(senate):
                            if senate[j] == 'R' and state[j] == 1:
                                state[j] = 2
                                flag = 2  # 已经投过票了
                                break
                            j += 1
                        if flag == 1:
                            j = 0
                            # 检查我前面的敌对参议员
                            while j < count:
                                if senate[j] == 'R' and state[j] == 1:
                                    state[j] = 2
                                    flag = 2
                                    break
                                j += 1
                # print(count, state)
                count += 1

        while 1:
            circle()
            first = ''
            end = ''
            count1, count2 = 0, 0
            while count1 < len(senate):
                if state[count1] != 2:
                    first = senate[count1]
                    break
                count1 += 1
            while count2 < len(senate):
                if state[count2] != 2:
                    end = senate[count2]
                if first != end and end:
                    break
                count2 += 1
            # print(state, first, end)
            # print(state)
            if first == end:
                if first == 'D':
                    return "Dire"
                else:
                    return "Radiant"

 来看官方题解:

设置两个队列,存储R和D在原始数组中的索引(也就是发言顺序)

两个敌对阵营中,在队头的元素,发言早的禁用发言晚的

发言早的进入队尾,等待下一次发言

发言晚的直接出队

最后哪个队不空就是哪个队赢

class Solution(object):
    def predictPartyVictory(self, senate):
        n = len(senate)
        radiant = collections.deque()
        dire = collections.deque()
        
        for i, ch in enumerate(senate):
            if ch == "R":
                radiant.append(i)
            else:
                dire.append(i)
        
        while radiant and dire:
            if radiant[0] < dire[0]:
                radiant.append(radiant[0] + n)
            else:
                dire.append(dire[0] + n)
            radiant.popleft()
            dire.popleft()
        
        return "Radiant" if radiant else "Dire"

你可能感兴趣的:(算法练习,python,算法)