用正则表达式刷leetcode每日一题(2026/06/29)

用正则表达式刷力扣每日一题(2026/06/29)

2029. 石子游戏 IX

2029. 石子游戏 IX
查看正则表达式可视化匹配过程
更多的正则表达式解法,请看我的合集

using System.Text.RegularExpressions;
public class Solution {
    static Regex regex = new Regex(@"(?x)
^(?>
  (?>(?=[147]()|)(?>[258](?'1'){2}|\d)(?>(?'-2')(?'1')|){2}(?>(?'-1'){3}|((?'-1'))|){2})+
  (?((?'-2'))(?((?'-2'))(?#index is 2)()|(?#index is 1)())|(?#index is 0)())(?>,|$)
)+$
(?<=(?>(?'-5'){2}.)*)
(?(5)(?<=(?>(?'-4')(?'-3').)*)(?<=(?>(?'1')(?'-4').)*(?>(?'1')(?'-3').)*)(?'-1'){3}
  |(?'-3')(?'-4')
)", RegexOptions.Compiled);
    public bool StoneGameIX(int[] stones) {
        return regex.IsMatch(string.Join(",", stones));
    }
}
using System.Text.RegularExpressions;
public class Solution {
    static Regex regex = new Regex(@"(?x)
# ==================== 阶段一:扫描输入,分类统计 ====================
^                       # 字符串开头
(?>
  # --- 内层循环:逐个字符处理当前石头的每一位 ---
  (?>(?=[147]()|)       # Lookahead:若当前字符是 1/4/7(即 %3==1),向隐式组压入空捕获(c[1]++)
      (?>[258](?'1'){2} # 若当前字符是 2/5/8(即 %3==2),向命名组 ""1"" 压入 2 个空捕获(c[2] += 2)
      | \d)             # 否则(%3==0 的数字),仅匹配该字符,不做计数
      (?>(?'-2')(?'1')|){2}   # 从组 2 弹出,同时向组 1 压入;重复 2 次(中间寄存器转移)
      (?>(?'-1'){3}     # 尝试从组 1 连续弹出 3 次(消去一个完整的 3)
        | ((?'-1'))     # 若不足 3 但至少有 1,弹出 1 次,并把 ""余 1"" 记录到编号组 2
        |               # 若组 1 已空,什么都不做
      ){2}              # 重复两次后,编号组 2 的深度 = 当前数字对 ""状态索引"" 的贡献(0/1/2)
  )+                    # 内层 +:处理当前石头的每一位(个位数时只执行一次)

  # --- 根据 ""状态索引"" 将当前石头归类到 3 个状态桶 ---
  (?(
      (?'-2')           # 尝试从组 2 再弹一次
    )
      (?(
          (?'-2')       # 再弹一次
        )
          (?#index is 2) ()   # 组 2 原本 ≥2:向编号组 3 压栈(index=2 的桶)
        |
          (?#index is 1) ()   # 组 2 原本 =1:向编号组 4 压栈(index=1 的桶)
      )
    |
      (?#index is 0) ()       # 组 2 原本 =0:向编号组 5 压栈(index=0 的桶,即 c[0])
  )
  (?>,|$)               # 匹配逗号(下一个石头)或字符串结尾
)+$                     # 外层 +:循环处理所有石头,直到字符串结尾
# ==================== 阶段二:最终胜负判定 ====================
(?<=                    # 正向 lookbehind:从字符串末尾往回检查最终状态
  (?>(?'-5'){2}.)*     # 每次从组 5 弹出 2 个,同时匹配任意字符
                        # 若组 5 深度(c[0])为偶数,可刚好弹完;若为奇数,剩余 1 个
)
# --- 条件分支:根据 c[0] 的奇偶性走不同判定逻辑 ---
(?(5)                  # 如果组 5 还有剩余(即 c[0] 为奇数)→ 走奇数分支
  (?<=
    (?>(?'-4')(?'-3').)*    # 同时从组 4 和组 3 各弹 1 个并匹配字符
                              # 反复执行,把 min(c[1], c[2]) 完全配对消去
  )
  (?<=
    (?>(?'1')(?'-4').)*     # 若组 4 还有剩余(c[1] > c[2]),向组 1 转移
    (?>(?'1')(?'-3').)*     # 若组 3 还有剩余(c[2] > c[1]),向组 1 转移
                              # 执行后,组 1 的深度 = abs(c[1] - c[2])
  )
  (?'-1'){3}             # 要求组 1 还能再弹出 3 个
                          # 即 abs(c[1] - c[2]) > 2 → Alice 必胜
|
  # 偶数分支:c[0] 为偶数 → 判定 min(c[1], c[2]) > 0
  (?'-3')(?'-4')         # 同时从组 3 和组 4 各弹 1 个
# 只有当两者都非空时才能成功 # 即 min(c[1], c[2]) > 0 → Alice 必胜
)", RegexOptions.Compiled);
    public bool StoneGameIX(int[] stones) {
        return regex.IsMatch(string.Join(",", stones));
    }
}

文章摘自:https://www.cnblogs.com/regexdev/p/22502736