返回

LeetCode第28天,运筹帷幄,稳操胜券!

前端

在 LeetCode 的第 28 天征途中,我们踏上了博弈领域的探险之旅。博弈,是一场策略与运筹的较量,考验着我们的思维敏捷与决策智慧。

今天,我们将深入了解两个经典博弈问题:292. Nim 游戏和 209. 长度最小的子数组。

292. Nim 游戏

在 Nim 游戏中,有 n 堆石头,每一堆石头的数量不尽相同。两位玩家轮流操作,每次操作可以从任意一堆石头中拿走任意数量的石头。当所有石头都被拿走时,后拿走石头的玩家获胜。

问题: 作为先手,如何才能保证必胜?

思路:

  • 找出所有石子数为 4 的倍数的堆。
  • 如果石子数为 4 的倍数的堆的个数为奇数,则先手必胜。
  • 否则,先手必败。

代码示例:

def can_win_nim(n: int) -> bool:
  """
  判断先手能否必胜。

  Args:
    n: 石子堆的数量。

  Returns:
    True 如果先手必胜,否则 False。
  """

  return n % 4 != 0

209. 长度最小的子数组

给定一个正整数数组 nums 和一个目标值 target,要求找出数组中长度最小的连续子数组,使得该子数组的和大于或等于 target。

问题:

  • 如何找到满足条件的长度最小的子数组?

思路:

  • 使用双指针法。
  • 一个指针指向子数组的起始位置,另一个指针指向子数组的结束位置。
  • 逐渐扩大子数组的范围,直到其和大于或等于 target。
  • 记录此时子数组的长度。

代码示例:

def min_sub_array_len(target: int, nums: List[int]) -> int:
  """
  找到满足条件的长度最小的子数组。

  Args:
    target: 目标值。
    nums: 正整数数组。

  Returns:
    满足条件的长度最小的子数组的长度。
  """

  if not nums:
    return 0

  left, right = 0, 0
  min_len = len(nums) + 1
  total = 0

  while right < len(nums):
    total += nums[right]
    while total >= target:
      min_len = min(min_len, right - left + 1)
      total -= nums[left]
      left += 1

    right += 1

  return min_len if min_len <= len(nums) else 0