比赛的赢家
问题描述
小M正在玩一个数组比赛游戏,游戏规则如下:每回合游戏都在所有元素互不相同的数组 arr 的前两个元素 arr[0] 和 arr[1] 之间进行。较大的整数将会取得这一回合的胜利并保留在位置 0,而较小的整数则会被移至数组的末尾。比赛继续,直到某个整数连续赢得 k 次,这个整数即为比赛的赢家。
给定一个整数数组 arr 和一个整数 k,请你返回赢得比赛的整数。题目数据保证游戏中一定存在赢家。
测试样例
样例1:
输入:
arr = [2, 1, 3, 5, 4, 6, 7, 9],k = 2
输出:5
样例2:
输入:
arr = [3, 2, 1, 4],k = 10
输出:4
样例3:
输入:
arr = [1, 9, 8, 7, 6, 5, 4, 3, 2, 11],k = 7
输出:9
数据结构选择
算法一 使用数组
思路分析
- 每次比较数组的前两个元素,然后将较大的元素放在数组的开头,较小的元素放在数组的末尾。
- 缺点是每次移动元素时需要遍历数组,时间复杂度较高。
代码实现
public class Main {
public static int solution(int[] arr, int k) {
// write code here
int winCnt = 0;
int formerWinNum = arr[0];
int currentWinNum;
int loseNum;
while(winCnt != k){
currentWinNum = arr[0] > arr[1] ? arr[0] : arr[1];
loseNum = arr[0] < arr[1] ? arr[0] : arr[1];
arr[0] = currentWinNum;
for(int i = 1; i < arr.length - 1; i++){
arr[i] = arr[i + 1];
}
arr[arr.length - 1] = loseNum;
if(formerWinNum == currentWinNum){
winCnt++;
}else{
formerWinNum = currentWinNum;
winCnt = 1;
}
}
return formerWinNum; // Placeholder return
}
public static void main(String[] args) {
int[] arr1 = {2, 1, 3, 5, 4, 6, 7, 9};
System.out.println(solution(arr1, 2) == 5);
int[] arr2 = {3, 2, 1, 4};
System.out.println(solution(arr2, 10) == 4);
int[] arr3 = {1, 9, 8, 7, 6, 5, 4, 3, 2, 11};
System.out.println(solution(arr3, 7) == 9);
}
}
算法二 使用双端队列(Deque)
思路分析
- 使用双端队列可以优化数组操作。每次比较队列的前两个元素,然后将较大的元素放在队列的开头,较小的元素放在队列的末尾。
- 这种方法的时间复杂度较低,因为双端队列可以在常数时间内进行头尾元素的插入和删除操作。
具体思路
-
-
初始化阶段:
- 创建一个双端队列
deque,用于存储整数数组中的元素。遍历给定的整数数组arr,将每个元素依次添加到双端队列的末尾。 - 初始化变量
winCnt为 0,表示当前连续获胜的次数;初始化变量formerWinNum为双端队列的第一个元素,即初始状态下的获胜数字。
-
-
-
循环模拟游戏过程:
-
使用
while循环,条件是winCnt < k,即当连续获胜次数未达到k时持续循环。 -
在每次循环中:
- 从双端队列头部取出两个元素,分别记为
first和second。 - 比较
first和second的大小,得到当前获胜数字currentWinNum(较大值)和失败数字loseNum(较小值)。 - 将当前获胜数字添加回双端队列的头部,失败数字添加到双端队列的尾部。
- 如果当前获胜数字与上一次的获胜数字
formerWinNum相同,则连续获胜次数winCnt增加;否则,更新formerWinNum为当前获胜数字,并且将连续获胜次数重置为 1。
- 从双端队列头部取出两个元素,分别记为
-
代码实现
import java.util.ArrayDeque;
import java.util.Deque;
public class Main {
public static int solution(int[] arr, int k) {
// 使用双端队列来优化数组操作
Deque<Integer> deque = new ArrayDeque<>();
for (int num : arr) {
deque.addLast(num);
}
int winCnt = 0;
int formerWinNum = deque.peekFirst();
while (winCnt < k) {
int first = deque.pollFirst();
int second = deque.pollFirst();
int currentWinNum = Math.max(first, second);
int loseNum = Math.min(first, second);
deque.addFirst(currentWinNum);
deque.addLast(loseNum);
if (formerWinNum == currentWinNum) {
winCnt++;
} else {
formerWinNum = currentWinNum;
winCnt = 1; // 重新开始计数
}
}
return formerWinNum;
}
public static void main(String[] args) {
int[] arr1 = {2, 1, 3, 5, 4, 6, 7, 9};
System.out.println(solution(arr1, 2) == 5);
int[] arr2 = {3, 2, 1, 4};
System.out.println(solution(arr2, 10) == 4);
int[] arr3 = {1, 9, 8, 7, 6, 5, 4, 3, 2, 11};
System.out.println(solution(arr3, 7) == 9);
}
}
补充知识(Java ArrayDeque)
创建ArrayDeque
- 为创建ArrayDeque双端队列,必须导入java.util.ArrayDeque包。
- 创建ArrayDeque
- ArrayDeque ArrayDeque名 = new ArrayDeque<>();
ArrayDeque方法
- 插入
- 使用add(),addFirst(),addLast()插入元素 //如果ArrayDeque双端队列已满,会抛出IllegalStateException异常
- add() - 将指定元素插入ArrayDeque双端队列的队尾
- addFirst() - 将指定元素插入ArrayDeque双端队列的队头
- addLast() - 将指定元素插入ArrayDeque双端队列的队尾
- 使用offer(),offerFirst(),offerLast()插入元素并返回是否成功插入元素 //如果ArrayDeque双端队列已满,返回false
- offer() - 将指定元素插入ArrayDeque双端队列的队尾
- offerFirst() - 将指定元素插入ArrayDeque双端队列的队头
- offerLast() - 将指定元素插入ArrayDeque双端队列的队尾
- 使用add(),addFirst(),addLast()插入元素 //如果ArrayDeque双端队列已满,会抛出IllegalStateException异常
- 访问
- 使用getFirst(),getLast()访问元素 // 如果ArrayDeque双端队列为空,会抛出NoSuchElementException异常
- getFirst() - 返回ArrayDeque双端队列的队头元素
- getLast() - 返回ArrayDeque双端队列的队尾元素
- 使用peek(),peekFirst(),peekLast()访问元素 // 如果ArrayDeque双端队列为空,会抛出NoSuchElementException异常
- peek() - 返回ArrayDeque双端队列的队头元素
- peekFirst() - 返回ArrayDeque双端队列的队头元素
- peekLast() - 返回ArrayDeque双端队列的队尾元素
- 使用getFirst(),getLast()访问元素 // 如果ArrayDeque双端队列为空,会抛出NoSuchElementException异常
- 删除
- 使用remove(),removeFirst(),removeLast()删除元素 // 如果ArrayDeque双端队列为空,会抛出异常
- remove() - 返回并删除ArrayDeque双端队列的队头元素
- removeFirst() - 返回并删除ArrayDeque双端队列的队头元素
- removeLast() - 返回并删除ArrayDeque双端队列的队尾元素
- remove(element) - 返回并删除ArrayDeque双端队列的指定元素element // 如果找不到元素,会抛出异常
- 使用poll(),pollFirst(),pollLast()删除元素 // 如果ArrayDeque双端队列为空,返回null
- poll() - 返回并删除ArrayDeque双端队列的队头元素
- pollFirst() - 返回并删除ArrayDeque双端队列的队头元素
- pollLast() - 返回并删除ArrayDeque双端队列的队尾元素
- clear() - 删除ArrayDeque双端队列的所有元素
- 使用remove(),removeFirst(),removeLast()删除元素 // 如果ArrayDeque双端队列为空,会抛出异常