1. 程式人生 > 其它 >Dota2參議院

Dota2參議院

技術標籤:leetcode

Dota2參議院

Dota2的世界裡有兩個陣營:Radiant天輝和Dire夜魘
Dota2參議院由來自兩派的參議員組成。現在參議院希望對一個Dota2遊戲裡的改變作出決定。他們以一個基於輪轉過程的投票進行。在每一輪中,每一位參議員都可以行使兩項權利中的一項:

  • 禁止一名參議員的權利:參議員可以讓另一位參議員在這一輪和隨後的幾輪中喪失所有的權利。
  • 宣佈勝利:如果參議員發現有權利投票的參議員都是同一個陣營的,他可以宣佈勝利並決定在遊戲中的有關變化。

給定一個字串代表每個參議員的陣營。字母RD分別代表了Radiant天輝和Dire夜魘。然後,如果有n個參議員,給定字串的大小將是n


以輪為基礎的過程從給定順序的第一個參議員開始到最後一個參議員結束。這一過程將持續到投票結束。所有失去權利的參議員將在過程中被跳過。
假設每一位參議員都足夠聰明,會為自己的政黨做出最好的策略,你需要預測哪一方最終會宣佈勝利並在Dota2遊戲中決定改變。輸出應該是RadiantDire

示例

輸入:"RD"
輸出:"Radiant"
解釋:第一個參議員來自 Radiant 陣營並且他可以使用第一項權利讓第二個參議員失去權力,因此第二個參議員將被跳過因為他沒有任何權利。然後在第二輪的時候,第一個參議員可以宣佈勝利,因為他是唯一一個有投票權的人
輸入:"RDD"
輸出:"Dire"
解釋:
第一輪中,第一個來自 Radiant 陣營的參議員可以使用第一項權利禁止第二個參議員的權利
第二個來自 Dire 陣營的參議員會被跳過因為他的權利被禁止
第三個來自 Dire 陣營的參議員可以使用他的第一項權利禁止第一個參議員的權利
因此在第二輪只剩下第三個參議員擁有投票的權利,於是他可以宣佈勝利

題解

/**
 * @param {string} senate
 * @return {string}
 */
var predictPartyVictory = function(senate) {
    const dire = [];
    const radiant = [];
    const n = senate.length;

    [...senate].forEach((v, i) => {
        if (v === "R") radiant.push(i);
        else dire.push(i);
    })

    while
(radiant.length && dire.length) { if(radiant[0] < dire[0]) radiant.push(radiant[0] + n); else dire.push(dire[0] + n); radiant.shift(); dire.shift(); } return radiant.length ? "Radiant" : "Dire"; };

思路

問題比較長,對於這個問題使用佇列模擬投票過程即可,使用貪心演算法,對於每個議員當輪到他時,則行駛第一個權利將其後方最近的一個地方陣營的議員的權利禁用,不斷進行幾輪,直到某一方的議員的權利全部被禁用,那麼剩下的一方就是獲勝者。官方的例子:當一名天輝方的議員行使權利時,如果目前所有的議員都為天輝方,那麼該議員可以直接宣佈天輝方取得勝利;如果目前仍然有夜魘方的議員,那麼這名天輝方的議員只能行使「禁止一名參議員的權利」這一項權利。顯然,該議員不會令一名同為天輝方的議員喪失權利,所以他一定會挑選一名夜魘方的議員。那麼應該挑選哪一名議員呢?容易想到的是,應該貪心地挑選按照投票順序的下一名夜魘方的議員。這也是很容易形象化地證明的:既然只能挑選一名夜魘方的議員,那麼就應該挑最早可以進行投票的那一名議員;如果挑選了其它較晚投票的議員,那麼等到最早可以進行投票的那一名議員行使權利時,一名天輝方議員就會喪失權利,這樣就得不償失了。題目參考了官方題解,我最初的想法是使用一個數組進行模擬,但是這樣會定義一個內層迴圈,複雜度直上O(n^2),所以參考了官方題解使用兩個佇列radiantdire,分別按照投票順序儲存天輝方和夜魘方每一名議員的投票時間。首先定義direradiant佇列以及n佇列長度,之後將字串轉為陣列,遍歷字串將各個議員的索引分別置放於各自的佇列,注意此處放置的是索引值,之後定義迴圈,當兩個佇列都不為空時執行,如果radiant的第一個值儲存的索引值小於dire第一個值儲存的索引值,那麼就將該值加n索引繼續放置到佇列,對應的是該議員行使完權利之後放到下一輪,反之亦然,之後將兩個佇列的隊首置出,他們在本輪迴圈都應該移除,只不過有一方是行使完權利加到了下一輪佇列,而另一方是因為被禁止行使權利而禁言了,最後判斷哪個佇列還有大使,返回即可。

每日一題

https://github.com/WindrunnerMax/EveryDay

參考

https://leetcode-cn.com/problems/dota2-senate/