leetcode
leetcode 1401 ~ 1450
找出数组游戏的赢家

找出数组游戏的赢家

难度:

标签:

题目描述

给你一个由 不同 整数组成的整数数组 arr 和一个整数 k

每回合游戏都在数组的前两个元素(即 arr[0]arr[1] )之间进行。比较 arr[0]arr[1] 的大小,较大的整数将会取得这一回合的胜利并保留在位置 0 ,较小的整数移至数组的末尾。当一个整数赢得 k 个连续回合时,游戏结束,该整数就是比赛的 赢家

返回赢得比赛的整数。

题目数据 保证 游戏存在赢家。

 

示例 1:

输入:arr = [2,1,3,5,4,6,7], k = 2
输出:5
解释:一起看一下本场游戏每回合的情况:

因此将进行 4 回合比赛,其中 5 是赢家,因为它连胜 2 回合。

示例 2:

输入:arr = [3,2,1], k = 10
输出:3
解释:3 将会在前 10 个回合中连续获胜。

示例 3:

输入:arr = [1,9,8,2,3,7,6,4,5], k = 7
输出:9

示例 4:

输入:arr = [1,11,22,33,44,55,66,77,88,99], k = 1000000000
输出:99

 

提示:

  • 2 <= arr.length <= 10^5
  • 1 <= arr[i] <= 10^6
  • arr 所含的整数 各不相同
  • 1 <= k <= 10^9

代码结果

运行时间: 44 ms, 内存: 26.6 MB


import java.util.*;
import java.util.stream.*;

/**
 * This class contains a method to find the winner of a game using Java Streams.
 * The method iterates over the array comparing the first two elements, keeps the larger
 * element at the front and moves the smaller element to the end. It keeps track of the
 * consecutive wins of the current front element, and when it reaches k, returns that element
 * as the winner.
 */
public class GameWinnerStream {
    public static int getWinner(int[] arr, int k) {
        Deque<Integer> deque = new ArrayDeque<>();
        Arrays.stream(arr).forEach(deque::offer);

        int currentWinner = deque.poll();
        int winCount = 0;

        while (winCount < k) {
            int challenger = deque.poll();
            if (challenger > currentWinner) {
                deque.offer(currentWinner);
                currentWinner = challenger;
                winCount = 1;
            } else {
                deque.offer(challenger);
                winCount++;
            }
        }

        return currentWinner;
    }

    public static void main(String[] args) {
        int[] arr1 = {2, 1, 3, 5, 4, 6, 7};
        int k1 = 2;
        System.out.println(getWinner(arr1, k1)); // Output: 5

        int[] arr2 = {3, 2, 1};
        int k2 = 10;
        System.out.println(getWinner(arr2, k2)); // Output: 3

        int[] arr3 = {1, 9, 8, 2, 3, 7, 6, 4, 5};
        int k3 = 7;
        System.out.println(getWinner(arr3, k3)); // Output: 9

        int[] arr4 = {1, 11, 22, 33, 44, 55, 66, 77, 88, 99};
        int k4 = 1000000000;
        System.out.println(getWinner(arr4, k4)); // Output: 99
    }
}

解释

方法:

此题解采用模拟比赛的方式进行。首先,检查k是否大于等于数组长度减一,如果是,直接返回数组中的最大值,因为最大的元素一定能够在足够多的回合中连续获胜。否则,使用变量cur来记录当前连胜的数字,tmp来记录当前数字还需要赢得多少回合才能成为赢家。遍历数组中的元素,如果cur大于当前元素,则cur的连胜次数(tmp)减一;如果小于,更新cur为当前元素,并重置tmp为k-1。如果tmp降到0,则当前cur为赢家,直接返回。如果遍历结束后没有找到赢家,则返回最后的cur,因为它已经是剩下的最大值。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
在算法中,你是如何确定当k大于等于数组长度减一时,返回数组中的最大值就是最优解的?
当k大于等于数组长度减一时,任何数字都至少有机会与数组中的其他所有数字比较一次。在这种情况下,数组中的最大值在遍历过程中总能持续获胜,因为它总是大于与之比较的任何其他数字。因此,最大值将可以连续获胜,直到它超过k次获胜,确保它是游戏的最终赢家。这就是为什么直接返回数组中的最大值是最优解的原因。
🦆
为什么选择使用两个变量cur和tmp来追踪当前赢家和剩余胜利次数?有没有可能用其他数据结构来优化这个过程?
使用变量cur和tmp的方法简单且直接。变量cur用来追踪当前可能的赢家,而tmp用来记录该赢家还需要赢得多少次比赛才能确保胜利。这种方法的优点是空间复杂度低(O(1)),并且能够快速更新赢家和胜利次数。使用其他复杂数据结构,如队列或堆,可能增加实现复杂度,而且在这种特定场景下,并不会提供额外的性能优势,因为我们需要跟踪的只是当前的领先者和它还需赢得的比赛次数。
🦆
在循环中,当当前元素cur大于数组中的下一个元素时,为什么tmp需要减1?这是否意味着每次比较都默认cur已经赢得了一局?
是的,根据题目的游戏规则,每次比较都代表一局比赛。当cur大于下一个元素时,这意味着cur赢得了这一局比赛,因此tmp(记录cur还需要赢得的比赛次数)需要减1。这样的设计确保了每次cur赢得比赛时,我们都逐步逼近它成为最终的赢家。
🦆
如果在某一次比较中,新的元素比cur大,tmp被重置为k-1。这种做法是否考虑了之前cur赢得的所有比赛?
这种做法确实没有将cur之前的胜利纳入新的计算中,因为一旦出现一个更大的元素,这个元素就成为新的‘赢家候选’,并且需要重新计算其胜利的场次。这是因为游戏规则是连续获胜,一旦有新的更大元素出现,之前的赢家的连胜记录就被打断,新的赢家需要开始新的连胜记录。

相关问题