问题序号:72
题目难度:简单
问题描述:
小S玩起了多米诺骨牌,他排列了一行骨牌,并可能将某些骨牌向左或向右推倒。随着骨牌连锁反应的进行,一些骨牌可能因为左右两侧受力平衡而保持竖立。现在小S想要知道在所有动作完成后,哪些骨牌保持竖立。
给定一个表示骨牌初始状态的字符串,其中:
- "L" 表示该位置的骨牌将向左倒。
- "R" 表示该位置的骨牌将向右倒。
- "." 表示该位置的骨牌初始时保持竖立。
模拟整个骨牌倒下的过程,求出最终仍然保持竖立的骨牌的数目和位置。
测试用例:
1.题目理解
这道题目虽然是简单题,但是还是不太好找到解题思路的,我感觉应该算中等题的说。
首先要看到当前的字符串中只包括三种状态,然后比较特别的是骨牌可能会因为受力平衡而保持竖立,而且根据最后的结果而言,这道题应该是假设了一张垂直多米诺骨牌的两侧同时有多米诺骨牌倒下时,该骨牌仍然保持不变,同时一张正在倒下的多米诺骨牌不会对其它正在倒下或已经倒下的多米诺骨牌施加额外的力
之后我们再开始想解题思路,首先根据上面的假设,那么对于一个竖直的多米诺一共有四种可能,我们只需要根据这四种可能进行判断即可
'R...R' => 'RRRRR'
'R......L' => 'RRRLLL' or 'RRRR.LLLL'
'L....R' => 'L....R'
'L...L' => 'LLLLL'
处于需要判断左右两边的状态,所以此题不妨采用双指针,左右两侧的状态,然后得到最后的结果,需要注意的是中间无论添加多少个竖直的多米诺骨牌都不影响。
2.代码(C艹)
#include <iostream>
#include <string>
using namespace std;
// 获取到推倒完毕之后的多米诺骨牌
string pushDominoes(string dominoes)
{
dominoes = "L" + dominoes + "R";
int l = 0;
string res = "";
for (int r = 1; r < dominoes.size(); r++)
{
if (dominoes[r] == '.')
{
continue;
}
if (l != 0)
{
res += dominoes[l];
}
int mid = r - l - 1;
if (dominoes[l] == dominoes[r])
{
res += string(mid, dominoes[l]);
}
else if (dominoes[l] == 'L' && dominoes[r] == 'R')
{
res += string(mid, '.');
}
else if (dominoes[l] == 'R' && dominoes[r] == 'L')
{
res += string(mid / 2, 'R') + (mid % 2 == 1 ? "." : "") + string(mid / 2, 'L');
}
l = r;
}
return res;
}
std::string solution(int num, std::string data)
{
string dominoes = pushDominoes(data);
string res;
int count = 0;
for (int i = 0; i < dominoes.size(); i++)
{
if (dominoes[i] == '.')
{
count++;
//此处需要注意该题是从1开始计算多米诺骨牌的,所以要写i+1
res += (to_string(i+1) + ",");
}
}
if (count == 0)
{
return "0";
}
else
{
res = to_string(count) + ":" + res;
res = res.substr(0, res.length() - 1);
}
return res;
}
int main()
{
// You can add more test cases here
std::cout << (solution(14, ".L.R...LR..L..") == "4:3,6,13,14") << std::endl;
std::cout << (solution(5, "R....") == "0") << std::endl;
std::cout << (solution(1, ".") == "1:1") << std::endl;
return 0;
}
3.代码讲解
为了防止边界的两个多米诺骨牌不方便使用代码进行判断,需要首先在边界加入一个向左和向右的骨牌。
开始遍历,如果遇到竖直的多米诺骨牌就继续,直到左右两侧都出现了非竖直的多米诺骨牌,此时即可按照按照四种情况进行判断,
左右两侧相同,则中间的都会朝同一个方向倒下;
左侧向右倒,右侧向左倒,则中间需要看是否为奇数,如果是奇数,那么中间的会平衡,反之则一半向右,一半向左;
如果左侧向左倒,右侧向右倒,那么中间就全部竖直。
之后不断遍历,判断完一部分就使用l==r来进行同步,判断下一截的状态。
最后按照题目要求,回到solution函数进行整理即可,主要就是先计算当前还有多少个“.”,以及在字符串的位置,不复杂。
4.时间复杂度分析
利用双指针从左向右遍历即可,获取到竖直多米诺骨牌数量和位置也只需要再遍历一次,所以时间复杂度是O(n),还是比较高效的方法