因此只需要关注初始状态为 .
的, 以及哪个被推倒的(L/R
)最先影响到它.
pub fn push_dominoes(dominoes: String) -> String {
let mut dominoes = dominoes;
let s = unsafe { dominoes.as_bytes_mut() };
// 只需要关注前面最后一个向右倒的, 以及后面最早一个向左倒的
// 其他组合不会影响当前的状态, 可以不记录
let (mut last_right, mut next_left): (Option<usize>, Option<usize>) = (None, None);
let mut cursor = 0;
while cursor < s.len() {
if s[cursor] == b'R' {
last_right.replace(cursor);
} else if s[cursor] == b'L' {
last_right.take();
} else if s[cursor] == b'.' {
next_left.take();
for j in cursor + 1..s.len() {
if s[j] == b'L' {
next_left.replace(j);
break;
} else if s[j] == b'R' {
break;
}
}
if last_right.is_none() && next_left.is_none() {
// 不变
} else if last_right.is_none() {
s[cursor] = b'L';
} else if next_left.is_none() {
s[cursor] = b'R';
} else {
let (r, l) = (last_right.unwrap(), next_left.unwrap());
match (cursor - r).cmp(&(l - cursor)) {
std::cmp::Ordering::Equal => {}
std::cmp::Ordering::Greater => {
s[cursor] = b'L';
}
std::cmp::Ordering::Less => {
s[cursor] = b'R';
}
}
}
// last_right.take();
// if s[cursor] == b'R' {
// last_right.replace(cursor);
// }
}
cursor += 1;
}
dominoes
}
按照上面代码, 在R......L
这种只有两端的序列下, 效果最差, 复杂度达到\(O(n^2)\)
观察可知,
对于任意一个 .
只需要在其两端, 找到离它最近的两个变动的即可
同理对于任意连续的 .
也是可以的.
* 原本的R/L
都不会变
pub fn push_dominoes(dominoes: String) -> String {
let mut dominoes = dominoes;
let s = unsafe { dominoes.as_bytes_mut() };
let (mut cursor, mut last) = (0, None::<u8>);
while cursor < s.len() {
if s[cursor] == b'R' || s[cursor] == b'L' {
last.replace(s[cursor]);
cursor += 1;
continue;
}
let mut end = cursor;
while end + 1 < s.len() && s[end + 1] == b'.' {
end += 1;
}
let tmp = end + 1; // 暂存
let next = s.get(tmp).copied();
// cursor, end
match (last, next) {
(Some(b'R'), Some(b'L')) => {
while cursor < end {
s[cursor] = b'R';
s[end] = b'L';
cursor += 1;
end -= 1;
}
}
(_, Some(b'L')) => {
for i in cursor..tmp {
s[i] = b'L';
}
}
(Some(b'R'), _) => {
for i in cursor..tmp {
s[i] = b'R';
}
}
_ => {}
}
cursor = tmp;
}
dominoes
}
一次性处理一段连续的.
然后跳过, 这样最多遍历\(2n\)次, 时间复杂度\(O(n)\)