There are N
dominoes in a line, and we place each domino vertically upright.html
In the beginning, we simultaneously push some of the dominoes either to the left or to the right.數組
After each second, each domino that is falling to the left pushes the adjacent domino on the left.dom
Similarly, the dominoes falling to the right push their adjacent dominoes standing on the right.ide
When a vertical domino has dominoes falling on it from both sides, it stays still due to the balance of the forces.post
For the purposes of this question, we will consider that a falling domino expends no additional force to a falling or already fallen domino.this
Given a string "S" representing the initial state. S[i] = 'L'
, if the i-th domino has been pushed to the left; S[i] = 'R'
, if the i-th domino has been pushed to the right; S[i] = '.'
, if the i
-th domino has not been pushed.url
Return a string representing the final state. spa
Example 1:指針
Input: ".L.R...LR..L.." Output: "LL.RR.LLRRLL.."
Example 2:code
Input: "RR.L" Output: "RR.L" Explanation: The first domino expends no additional force on the second domino.
Note:
0 <= N <= 10^5
dominoes
contains only 'L
', 'R'
and '.'
這道題給咱們擺好了一個多米諾骨牌陣列,可是與通常的玩法不一樣的是,這裏沒有從一頭開始推,而是在不少不一樣的位置分別往兩個方向推,結果是骨牌各自向不一樣的方向倒下了,並且有的骨牌因爲左右兩邊受力均等,依然屹立不倒,這樣的話骨牌就很難受了,能不能讓哥安心的倒下去?!生而爲骨牌,老是要倒下去啊,就像漫天飛舞的櫻花,秒速五釐米的落下,回到最終歸宿泥土裏。喂,不要給骨牌強行加戲好麼!~ 某個位置的骨牌會不會倒,而且朝哪一個方向倒,是由左右兩邊受到的力的大小決定的,那麼能夠分爲下列四種狀況:
1)R....R -> RRRRRR
這是當兩個向右推的操做連在一塊兒時,那麼中間的骨牌毫無懸念的都要向右邊倒去。
2)L....L -> LLLLLL
同理,
當兩個向左推的操做連在一塊兒時,那麼中間的骨牌毫無懸念的都要向左邊倒去。
3)L....R -> L....R
當左邊界的骨牌向左推,右邊界的骨牌向右推,那麼中間的骨牌不會收到力,因此依然保持堅挺。
4)R....L -> RRRLLL or R.....L -> RRR.LLL
當左邊界的骨牌向右推,右邊界的骨牌向左推時,就要看中間的骨牌個數了,如果偶數,那麼對半分,如果奇數,那麼最中間的骨牌保持站立,其他的對半分。
因爲上述四種狀況包含了全部的狀況,因此咱們的目標就是在字符串中找出中間是‘點’的小區間,爲了便於咱們一次遍歷就處理完,咱們在dominoes字符串左邊加個L,右邊加個R,這並不會影響骨牌倒下的狀況。咱們使用雙指針來遍歷,其中i初始化爲0,j初始化爲1,當j指向‘點’時,咱們就跳過,目標是i指向小區間的左邊界,j指向右邊界,而後用 j-i-1 算出中間‘點’的個數,爲0表示中間沒有點。若此時 i>0,則將左邊界加入結果res中。若左右邊界相同,那麼中間的點都填成左邊界,這是上述的狀況一和二;若左邊界是L,右邊界是R,則是上述的狀況三,中間仍是保持點不變;若左邊界是R,右邊界是L,則是狀況四,那麼先加 mid/2 個R,再加 mid%2 個點,最後加 mid/2 個L便可。而後i更新爲j,繼續循環便可,參見代碼以下:
解法一:
class Solution { public: string pushDominoes(string dominoes) { string res = ""; dominoes = "L" + dominoes + "R"; for (int i = 0, j = 1; j < dominoes.size(); ++j) { if (dominoes[j] == '.') continue; int mid = j - i - 1; if (i > 0) res += dominoes[i]; if (dominoes[i] == dominoes[j]) res += string(mid, dominoes[i]); else if (dominoes[i] == 'L' && dominoes[j] == 'R') res += string(mid, '.'); else res += string(mid / 2, 'R') + string(mid % 2, '.') + string(mid / 2, 'L'); i = j; } return res; } };
下面這種解法遍歷了兩次字符串,第一次遍歷是先把R後面的點全變成R,同時累加一個cnt數組,其中cnt[i]表示在dominoes數組中i位置時R連續出現的個數,那麼拿題目中的例子1來講,第一次遍歷以後,原dominoes數組,修改後的dominoes數組,以及cnt數組分別爲:
.L.R...LR..L.. .L.RRRRLRRRL.. 00001230012000
咱們能夠發現cnt數字記錄的是R連續出現的個數,第一次遍歷只模擬了全部往右推倒的狀況,很明顯不是最終答案,由於還須要往左推,那麼就要把某些點變成L,已經把某些R變成點或者L,這時咱們的cnt數組就很是重要,由於它至關於記錄了往右推的force的大小。第二次遍歷是從右往左,咱們找全部L前面的位置,若其爲點,則直接變爲L。若其爲R,那麼也有可能變L,此時就要計算往左的force,經過 cnt[i+1] + 1 得到,而後跟往右的force比較,若此位置往右的force大,說明當前骨牌應該往左倒,更新此時cnt[i]爲往左的force。若此時左右force相等了,說明當前骨牌不會向任意一遍倒,改成點便可,最終修改後的dominoes數組和cnt數組分別爲:
LL.RR.LLRRLL.. 10001210011000
解法二:
class Solution { public: string pushDominoes(string dominoes) { int n = dominoes.size(); vector<int> cnt(n); for (int i = 1; i < n; ++i) { if (dominoes[i - 1] == 'R' && dominoes[i] == '.') { dominoes[i] = 'R'; cnt[i] = cnt[i - 1] + 1; } } for (int i = n - 2, cur = 0; i >= 0; --i) { if (dominoes[i + 1] != 'L') continue; cur = cnt[i + 1] + 1; if (dominoes[i] == '.' || cnt[i] > cur) { dominoes[i] = 'L'; cnt[i] = cur; } else if (dominoes[i] == 'R' && cnt[i] == cur) { dominoes[i] = '.'; } } return dominoes; } };
相似題目:
Shortest Distance to a Character
參考資料:
https://leetcode.com/problems/push-dominoes/
https://leetcode.com/problems/push-dominoes/discuss/132332/C%2B%2BJavaPython-Two-Pointers
https://leetcode.com/problems/push-dominoes/discuss/132932/C%2B%2B-2-pass-scan-O(2N)-13ms