Toasobi
Dota2 参议院(队列)
这道题一开始我想的是拼人头数,所以用的是栈的方式,下面是错误代码
public String predictPartyVictory(String senate) {
Stack<Character> stack = new Stack<>();
char[] chars = senate.toCharArray();
char head = chars[0];
stack.push(chars[0]);
for (int i = 1; i < chars.length; i++) {
if(!stack.isEmpty() && stack.peek() != chars[i]){
stack.pop();
}else{
stack.push(chars[i]);
}
}
if(!stack.isEmpty()){
return stack.pop() == 'R' ? "Radiant" : "Dire";
}else{
return head == 'R' ? "Radiant" : "Dire";
}
}
**
- 方法一:贪心 + 「循环」队列
**
使用两个队列存储投票顺序模拟投票过程
思路与算法
我们以天辉方的议员为例。当一名天辉方的议员行使权利时:
如果目前所有的议员都为天辉方,那么该议员可以直接宣布天辉方取得胜利;
如果目前仍然有夜魇方的议员,那么这名天辉方的议员只能行使「禁止一名参议员的权利」这一项权利。显然,该议员不会令一名同为天辉方的议员丧失权利,所以他一定会挑选一名夜魇方的议员。那么应该挑选哪一名议员呢?容易想到的是,应该贪心地挑选按照投票顺序的下一名夜魇方的议员。这也是很容易形象化地证明的:既然只能挑选一名夜魇方的议员,那么就应该挑最早可以进行投票的那一名议员;如果挑选了其他较晚投票的议员,那么等到最早可以进行投票的那一名议员行使权利时,一名天辉方议员就会丧失权利,这样就得不偿失了。
由于我们总要挑选投票顺序最早的议员,因此我们可以使用两个队列 radiant 和 dire 分别按照投票顺序存储天辉方和夜魇方每一名议员的投票时间。随后我们就可以开始模拟整个投票的过程:
如果此时 radiant 或者 dire 为空,那么就可以宣布另一方获得胜利;
如果均不为空,那么比较这两个队列的首元素,就可以确定当前行使权利的是哪一名议员。如果 radiant 的首元素较小,那说明轮到天辉方的议员行使权利,其会挑选 dire 的首元素对应的那一名议员。因此,我们会将 dire 的首元素永久地弹出,并将 radiant 的首元素弹出,增加 n 之后再重新放回队列,这里 n 是给定的字符串senate的长度,即表示该议员会参与下一轮的投票。
为什么这里是固定地增加 n ,而不是增加与当前剩余议员数量相关的一个数?读者可以思考一下这里的正确性。
这样一来,我们就模拟了整个投票的过程,也就可以得到最终的答案了。
代码如下:
class Solution {
public String predictPartyVictory(String senate) {
int n = senate.length();
Queue<Integer> radiant = new LinkedList<Integer>();
Queue<Integer> dire = new LinkedList<Integer>();
for (int i = 0; i < n; ++i) {
if (senate.charAt(i) == 'R') {
radiant.offer(i);
} else {
dire.offer(i);
}
}
while (!radiant.isEmpty() && !dire.isEmpty()) {
int radiantIndex = radiant.poll(), direIndex = dire.poll();
if (radiantIndex < direIndex) {
radiant.offer(radiantIndex + n);
} else {
dire.offer(direIndex + n);
}
}
return !radiant.isEmpty() ? "Radiant" : "Dire";
}
}