普通视图

发现新文章,点击刷新页面。
今天 — 2025年12月4日LeetCode 每日一题题解

每日一题-统计道路上的碰撞次数🟡

2025年12月4日 00:00

在一条无限长的公路上有 n 辆汽车正在行驶。汽车按从左到右的顺序按从 0n - 1 编号,每辆车都在一个 独特的 位置。

给你一个下标从 0 开始的字符串 directions ,长度为 ndirections[i] 可以是 'L''R''S' 分别表示第 i 辆车是向 、向 或者 停留 在当前位置。每辆车移动时 速度相同

碰撞次数可以按下述方式计算:

  • 当两辆移动方向 相反 的车相撞时,碰撞次数加 2
  • 当一辆移动的车和一辆静止的车相撞时,碰撞次数加 1

碰撞发生后,涉及的车辆将无法继续移动并停留在碰撞位置。除此之外,汽车不能改变它们的状态或移动方向。

返回在这条道路上发生的 碰撞总次数

 

示例 1:

输入:directions = "RLRSLL"
输出:5
解释:
将会在道路上发生的碰撞列出如下:
- 车 0 和车 1 会互相碰撞。由于它们按相反方向移动,碰撞数量变为 0 + 2 = 2 。
- 车 2 和车 3 会互相碰撞。由于 3 是静止的,碰撞数量变为 2 + 1 = 3 。
- 车 3 和车 4 会互相碰撞。由于 3 是静止的,碰撞数量变为 3 + 1 = 4 。
- 车 4 和车 5 会互相碰撞。在车 4 和车 3 碰撞之后,车 4 会待在碰撞位置,接着和车 5 碰撞。碰撞数量变为 4 + 1 = 5 。
因此,将会在道路上发生的碰撞总次数是 5 。

示例 2:

输入:directions = "LLRR"
输出:0
解释:
不存在会发生碰撞的车辆。因此,将会在道路上发生的碰撞总次数是 0 。

 

提示:

  • 1 <= directions.length <= 105
  • directions[i] 的值为 'L''R''S'

【什码情况】分情况统计,两次遍历即可

作者 smqk
2022年3月20日 12:13

image.png

解题思路

分情况统计,两次遍历即可

代码

###java

class Solution {
    public int countCollisions(String directions) {
        char[] dirs = directions.toCharArray();
        int n = dirs.length, cnt = 0;

        // 统计 L 操作出现的碰撞次数
        boolean leftLimit = false;
        for (int i = 0; i < n; i++) {
            // 左侧有车辆 S 或 R 时,说明左侧有界(L操作肯定会碰撞)
            if (!leftLimit && dirs[i] != 'L') leftLimit = true;

            if (dirs[i] == 'L' && leftLimit) cnt++;
        }

        // 统计 R 操作出现的碰撞次数
        boolean rightLimit = false;
        for (int i = n - 1; i >= 0; i--) {
            // 右侧有车辆 S 或 L 时,说明右侧有界(R操作肯定会碰撞)
            if (!rightLimit && dirs[i] != 'R') rightLimit = true;
            if (dirs[i] == 'R' && rightLimit) cnt++;
        }

        return cnt;
    }
}

最后

如果有帮助到你,请给题解点个赞和收藏,让更多的人看到 ~ ("▔□▔)/

也欢迎加我微信『 code5bug 』和 加入我们的「组队打卡」小群。

脑筋急转弯(Python/Java/C++/C/Go/JS/Rust)

作者 endlesscheng
2022年3月20日 12:10

去掉前缀向左开、后缀向右开的车,剩下非停止($\ne \texttt{S}$)的车必然会碰撞。

class Solution:
    def countCollisions(self, s: str) -> int:
        s = s.lstrip('L')  # 前缀向左的车不会发生碰撞
        s = s.rstrip('R')  # 后缀向右的车不会发生碰撞
        return len(s) - s.count('S')  # 剩下非停止的车必然会碰撞
class Solution {
    public int countCollisions(String s) {
        int n = s.length();

        // 前缀向左的车不会发生碰撞
        int l = 0;
        while (l < n && s.charAt(l) == 'L') {
            l++;
        }

        // 后缀向右的车不会发生碰撞
        int r = n; 
        while (r > l && s.charAt(r - 1) == 'R') {
            r--;
        }

        // 剩下非停止的车必然会碰撞
        int cnt = 0; 
        for (int i = l; i < r; i++) {
            if (s.charAt(i) != 'S') {
                cnt++;
            }
        }
        return cnt;
    }
}
class Solution {
    public int countCollisions(String s) {
        s = s.replaceAll("^L+", ""); // 前缀向左的车不会发生碰撞
        s = new StringBuilder(s).reverse().toString().replaceAll("^R+", ""); // 后缀向右的车不会发生碰撞
        return (int) s.chars().filter(c -> c != 'S').count(); // 剩下非停止的车必然会碰撞
    }
}
class Solution {
public:
    int countCollisions(string s) { 
        int n = s.size();

        // 前缀向左的车不会发生碰撞
        int l = 0;
        while (l < n && s[l] == 'L') {
            l++;
        }

        // 后缀向右的车不会发生碰撞
        int r = n; 
        while (r > l && s[r - 1] == 'R') {
            r--;
        }

        // 剩下非停止的车必然会碰撞
        int cnt = 0; 
        for (int i = l; i < r; i++) {
            cnt += s[i] != 'S';
        }
        return cnt;
    }
};
class Solution {
public:
    int countCollisions(string s) {
        s.erase(s.begin(), ranges::find_if(s, [](auto c) { return c != 'L'; })); // 前缀向左的车不会发生碰撞
        s.erase(find_if(s.rbegin(), s.rend(), [](auto c) { return c != 'R'; }).base(), s.end()); // 后缀向右的车不会发生碰撞
        return s.length() - ranges::count(s, 'S'); // 剩下非停止的车必然会碰撞
    }
};
int countCollisions(char* s) { 
    // 前缀向左的车不会发生碰撞
    int l = 0;
    while (s[l] == 'L') {
        l++;
    }

    // 后缀向右的车不会发生碰撞
    int r = strlen(s); 
    while (r > l && s[r - 1] == 'R') {
        r--;
    }

    // 剩下非停止的车必然会碰撞
    int cnt = 0; 
    for (int i = l; i < r; i++) {
        cnt += s[i] != 'S';
    }
    return cnt;
}
func countCollisions(s string) int {
s = strings.TrimLeft(s, "L")          // 前缀向左的车不会发生碰撞
s = strings.TrimRight(s, "R")         // 后缀向右的车不会发生碰撞
return len(s) - strings.Count(s, "S") // 剩下非停止的车必然会碰撞
}
var countCollisions = function(s) { 
    const n = s.length;

    // 前缀向左的车不会发生碰撞
    let l = 0;
    while (l < n && s[l] === 'L') {
        l++;
    }

    // 后缀向右的车不会发生碰撞
    let r = n;
    while (r > l && s[r - 1] === 'R') {
        r--;
    }

    // 剩下非停止的车必然会碰撞
    let cnt = 0; 
    for (let i = l; i < r; i++) {
        if (s[i] !== 'S') {
            cnt++;
        }
    }
    return cnt;
};
impl Solution {
    pub fn count_collisions(s: String) -> i32 {
        let s = s.as_bytes();
        let n = s.len();

        // 前缀向左的车不会发生碰撞
        let mut l = 0;
        while l < n && s[l] == b'L' {
            l += 1;
        }

        // 后缀向右的车不会发生碰撞
        let mut r = n;
        while r > l && s[r - 1] == b'R' {
            r -= 1;
        }

        // 剩下非停止的车必然会碰撞
        s[l..r].iter().filter(|&&c| c != b'S').count() as _
    }
}

复杂度分析

  • 时间复杂度:$\mathcal{O}(n)$,其中 $n$ 是 $s$ 的长度。
  • 空间复杂度:$\mathcal{O}(n)$ 或 $\mathcal{O}(1)$。

分类题单

如何科学刷题?

  1. 滑动窗口与双指针(定长/不定长/单序列/双序列/三指针/分组循环)
  2. 二分算法(二分答案/最小化最大值/最大化最小值/第K小)
  3. 单调栈(基础/矩形面积/贡献法/最小字典序)
  4. 网格图(DFS/BFS/综合应用)
  5. 位运算(基础/性质/拆位/试填/恒等式/思维)
  6. 图论算法(DFS/BFS/拓扑排序/基环树/最短路/最小生成树/网络流)
  7. 动态规划(入门/背包/划分/状态机/区间/状压/数位/数据结构优化/树形/博弈/概率期望)
  8. 常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)
  9. 数学算法(数论/组合/概率期望/博弈/计算几何/随机算法)
  10. 贪心与思维(基本贪心策略/反悔/区间/字典序/数学/思维/脑筋急转弯/构造)
  11. 链表、树与回溯(前后指针/快慢指针/DFS/BFS/直径/LCA)
  12. 字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)

我的题解精选(已分类)

欢迎关注 B站@灵茶山艾府

答案 = 会被撞停的车辆数

作者 newhar
2022年3月20日 12:08

分析题意:

  • 当两辆移动方向 相反 的车相撞时,碰撞次数加 2 。--> 两辆车被撞停,答案 + 2。
  • 当一辆移动的车和一辆静止的车相撞时,碰撞次数加 1 。--> 一辆车被撞停,答案 +1。

显然,左侧的 $\texttt{'L'}$ 和右侧的 $\texttt{'R'}$ 不会被撞停;而中间的车辆都会最终停止,因此统计中间的、一开始没有停止的车辆数(即不是 $\texttt{'S'}$ 的车辆数)即可。

###c++

class Solution {
public:
    int countCollisions(string s) {
        int l = 0, r = s.size() - 1;
        while(l <= r && s[l] == 'L') ++l;
        while(l <= r && s[r] == 'R') --r;
        int res = 0; 
        for(int i = l; i <= r; ++i) if(s[i] == 'L' || s[i] == 'R') ++res;
        return res;
    }
};

如果没有想到这个方法,也没关系,下面给一个解决这类问题的常见套路:用栈模拟。(类似题目:LC 735. 行星碰撞)。

###c++

class Solution {
public:
    int countCollisions(string directions) {
        int res = 0;
        stack<char> st;
        for(char c : directions) {
            if(c == 'L') {
                // 只有之前有 'R' 或 'S' 时,才会被撞停
                if(st.size()) {
                    // 之前所有的向右行驶的车都会撞停
                    while(st.size() && st.top() == 'R') {
                        res += 1;
                        st.pop();
                    }
                    // 当前车也会被撞停
                    res += 1;
                    st.push('S');
                }
            } else if(c == 'S') {
                while(st.size() && st.top() == 'R') {
                    res += 1;
                    st.pop();
                }
                st.push('S');
            } 
            else { // c == 'R'
                // 向右行驶的车先暂存在栈里,留待之后检查
                st.push(c);
            }
        }
        return res;
    }
};
❌
❌