当前位置: 首页 > news >正文

每天一道算法题——推多米诺

目录

题目链接:838. 推多米诺 - 力扣(LeetCode)

题目描述

分析

解题思路 1:两次遍历(贪心 + 力传播)

核心思想:

🔧 实现步骤:

📌 示例说明:

✅ 解题思路 2:动态规划

🧠 核心思想:

✅ 总结

解法一:动态规划

Java写法:

C++写法:

运行时间

时间复杂度和空间复杂度

解法二:双遍历(贪心 + 力传播)

Java写法:

C++写法:

运行时间

时间复杂度和空间复杂度

总结


题目链接:838. 推多米诺 - 力扣(LeetCode)

注:下述题目描述和示例均来自力扣

题目描述

n 张多米诺骨牌排成一行,将每张多米诺骨牌垂直竖立。在开始时,同时把一些多米诺骨牌向左或向右推。

每过一秒,倒向左边的多米诺骨牌会推动其左侧相邻的多米诺骨牌。同样地,倒向右边的多米诺骨牌也会推动竖立在其右侧的相邻多米诺骨牌。

如果一张垂直竖立的多米诺骨牌的两侧同时有多米诺骨牌倒下时,由于受力平衡, 该骨牌仍然保持不变。

就这个问题而言,我们会认为一张正在倒下的多米诺骨牌不会对其它正在倒下或已经倒下的多米诺骨牌施加额外的力。

给你一个字符串 dominoes 表示这一行多米诺骨牌的初始状态,其中:

  • dominoes[i] = 'L',表示第 i 张多米诺骨牌被推向左侧,
  • dominoes[i] = 'R',表示第 i 张多米诺骨牌被推向右侧,
  • dominoes[i] = '.',表示没有推动第 i 张多米诺骨牌。

返回表示最终状态的字符串。

示例 1:

输入:dominoes = "RR.L"
输出:"RR.L"
解释:第一张多米诺骨牌没有给第二张施加额外的力。

示例 2:

输入:dominoes = ".L.R...LR..L.."
输出:"LL.RR.LLRRLL.."

提示:

  • n == dominoes.length
  • 1 <= n <= 10^5
  • dominoes[i] 为 'L''R' 或 '.'

分析

这个问题是一个经典的模拟类题目,关键在于如何高效地模拟多米诺骨牌倒下的过程。我们希望找出每个多米诺骨牌最终的状态(L、R 或 .)。下面是解决该问题的几种常见思路:


解题思路 1:两次遍历(贪心 + 力传播)

核心思想:

  • 每张未被推倒的多米诺骨牌会受到左右最近的“力”的影响。
  • 如果我们知道每个位置离它最近的左边的 R 和 最近的右边的 L 的距离,就可以判断它会被推向哪边。
  • 如果两个方向的力同时作用(距离相等),则保持直立。

🔧 实现步骤:

  1. 第一次从左到右扫描:
    • 记录每个位置被左边最近的 'R' 推动的时间(即距离)。
  2. 第二次从右到左扫描:
    • 记录每个位置被右边最近的 'L' 推动的时间(即距离)。
  3. 综合两个方向的力决定最终状态。

📌 示例说明:

输入:"RR.L"

  • 索引0: 'R',向右推
  • 索引1: 'R',向右推
  • 索引2: '.',受索引1的R影响,继续向右倒
  • 索引3: 'L'

最终输出:"RR.L"


✅ 解题思路 2:动态规划

🧠 核心思想:

  • 类似于双指针,但用 DP 数组记录每个位置最近的左/右施力点的距离。
  • 最后根据左右距离比较得出结果。

✅ 总结

方法时间复杂度空间复杂度是否推荐
双遍历法O(n)O(n)✅ 推荐,实现简单,效率高
BFS 法O(n)O(n)✅ 推荐,逻辑清晰
动态规划O(n)O(n)⭕ 可行,略复杂

解法一:动态规划

Java写法:

class Solution {public String pushDominoes(String dominoes) {int n = dominoes.length();int[] leftForce = new int[n];int force = 0;// 从左向右计算右向力for (int i = 0; i < n; i++) {if (dominoes.charAt(i) == 'R') {force = n; // 表示很强的右向力} else if (dominoes.charAt(i) == 'L') {force = 0; // 遇到L,清除右向力} else {force = Math.max(force - 1, 0);}leftForce[i] = force;}// 从右向左计算左向力,并比较决定最终方向force = 0;StringBuilder res = new StringBuilder();for (int i = n - 1; i >= 0; i--) {if (dominoes.charAt(i) == 'L') {force = n;} else if (dominoes.charAt(i) == 'R') {force = 0;} else {force = Math.max(force - 1, 0);}int diff = leftForce[i] - force;if (diff > 0) {res.append('R');} else if (diff < 0) {res.append('L');} else {res.append('.');}}return res.reverse().toString();}
}

C++写法:

#include <string>
#include <vector>
#include <algorithm>class Solution {
public:std::string pushDominoes(std::string dominoes) {int n = dominoes.size();const int INF = n + 1;std::vector<int> left(n, INF), right(n, INF);// 从左到右计算右侧力int force = INF;for (int i = 0; i < n; ++i) {if (dominoes[i] == 'R') {force = 0;} else if (dominoes[i] == 'L') {force = INF;} else {force = force == INF ? INF : force + 1;}right[i] = force;}// 从右到左计算左侧力force = INF;for (int i = n - 1; i >= 0; --i) {if (dominoes[i] == 'L') {force = 0;} else if (dominoes[i] == 'R') {force = INF;} else {force = force == INF ? INF : force + 1;}left[i] = force;}// 构造最终结果for (int i = 0; i < n; ++i) {if (right[i] < left[i]) {dominoes[i] = 'R';} else if (left[i] < right[i]) {dominoes[i] = 'L';} else {dominoes[i] = '.';}}return dominoes;}
};

运行时间

时间复杂度和空间复杂度

  • 时间复杂度: O(n),同样地,我们也进行了三次线性扫描,分别用于初始化、从左到右计算以及从右到左计算。
  • 空间复杂度: O(n),使用了两个辅助数组来存储每个位置的左右力值。



解法二:双遍历(贪心 + 力传播)

Java写法:

class Solution {public String pushDominoes(String dominoes) {int n = dominoes.length();char[] d = dominoes.toCharArray();int[] rightForce = new int[n];int[] leftForce = new int[n];// 从左到右计算右边方向的力int force = 0;for (int i = 0; i < n; i++) {if (d[i] == 'R') {force = n;  // 最强向右力} else if (d[i] == 'L') {force = 0;  // 遇到L则清除向右力} else {force = Math.max(force - 1, 0);}rightForce[i] = force;}// 从右到左计算左边方向的力force = 0;for (int i = n - 1; i >= 0; i--) {if (d[i] == 'L') {force = n;  // 最强向左力} else if (d[i] == 'R') {force = 0;  // 遇到R则清除向左力} else {force = Math.max(force - 1, 0);}leftForce[i] = force;}// 比较左右力决定结果StringBuilder res = new StringBuilder();for (int i = 0; i < n; i++) {if (rightForce[i] > leftForce[i]) {res.append('R');} else if (rightForce[i] < leftForce[i]) {res.append('L');} else {res.append('.');}}return res.toString();}
}

C++写法:

#include <string>
#include <vector>
#include <algorithm>class Solution {
public:std::string pushDominoes(std::string dominoes) {int n = dominoes.size();std::vector<int> rightForce(n, 0);std::vector<int> leftForce(n, 0);// 计算右侧力int force = 0;for (int i = 0; i < n; ++i) {if (dominoes[i] == 'R') {force = n; // 强右向力} else if (dominoes[i] == 'L') {force = 0; // 清除右向力} else {force = std::max(force - 1, 0);}rightForce[i] = force;}// 计算左侧力force = 0;for (int i = n - 1; i >= 0; --i) {if (dominoes[i] == 'L') {force = n; // 强左向力} else if (dominoes[i] == 'R') {force = 0; // 清除左向力} else {force = std::max(force - 1, 0);}leftForce[i] = force;}// 根据左右力决定最终状态for (int i = 0; i < n; ++i) {if (rightForce[i] > leftForce[i]) {dominoes[i] = 'R';} else if (leftForce[i] > rightForce[i]) {dominoes[i] = 'L';} else {dominoes[i] = '.';}}return dominoes;}
};

运行时间

时间复杂度和空间复杂度

  • 时间复杂度: O(n),其中 n 是字符串 dominoes 的长度。我们对字符串进行了三次线性扫描。
  • 空间复杂度: O(n),我们需要额外的空间来存储左右两边的力值数组。

总结

        奥耶~~~~

相关文章:

  • leetcode 838. 推多米诺 中等
  • A2A Python 教程 - 综合指南
  • 深度理解linux系统—— 进程切换和调度
  • 数据结构-线性结构(链表、栈、队列)实现
  • Python 中 DAO 层使用泛型的探索
  • 接口测试实战指南:从入门到精通的质量保障之道
  • Linux系统:详解文件描述符与重定向原理以及相关接口(open,read,write,dup2)
  • 分布式理论:常见分布式协议的概览与解析
  • 51c大模型~合集123
  • C++ 复习
  • AI驱动文字冒险游戏
  • 第 12 届蓝桥杯 C++ 青少组中 / 高级组省赛 2021 年真题
  • 0基础 | STM32 | STM32F103C8T6开发板 | 项目开发
  • #以梦为楫,共航中医传承新程
  • 芯片中的pad、strap和probe
  • Proxmox VE 8.4 显卡直通完整指南:NVIDIA 2080 Ti 实战
  • 深度学习与 PyTorch 基础
  • WindowsPE文件格式入门10.TLS表
  • Day108 | 灵神 | 合并两个有序链表
  • Matlab自学笔记
  • “矿茅”国际化才刚开始?紫金矿业拟分拆境外黄金矿山资产于港交所上市
  • 2025年五一档电影票房破4亿,《水饺皇后》领跑
  • 徐丹任武汉大学药学院院长:研究领域在国际上处领跑地位
  • 赵厚均评《唐诗与唐代园林景观的审美建构研究》|林泉恣探历,风景暂徘徊
  • 解放日报:“北斗七星”列阵,AI群星闪耀
  • 媒体:酒店、民宿临时毁约涨价,怎么管?