Java 中的 Codility 传递汽车问题

2025年1月7日 | 阅读 4 分钟

Codility Passing Cars 问题 是众多典型的算法问题之一,其主要目标是确定在同一条道路上朝相反方向行驶的汽车的有效对的总数。

更具体地说,该问题要求计算向东行驶的汽车(由 0 表示)与向西行驶的汽车(由 1 表示)相遇的次数。

难度在于最有效地解决这个问题;也就是说,最好是 O(N) 时间复杂度,其中 N 是数组的总元素数量。

问题陈述

给定一个由 N 个整数组成的数组 A,每个元素代表一辆汽车的方向

  • '0' 表示一辆向东行驶的汽车。
  • 1 表示一辆向西行驶的汽车。

你的目标是定义(多少)对 (P, Q) 存在,其中 P 小于 Q,位置 P 的元素 A[P] = 0,位置 Q 的元素 A[Q] = 1。换句话说,你想知道一种量化从东方来的汽车会超车另一辆来自西方的车辆的概率的方法。

问题解决方案

该解决方案利用了这样一个事实:对于每一个在西行车上的“1”,都有它前面的所有“0”代表东行车。这使得我们能够通过单次扫描数组来计算通过对,因此,时间复杂度将是 O(N)。

我们维护两个计数器

  • num_east:记录以零为特征的向东行驶的汽车数量。
  • num_pass:记录一辆东行汽车超车一辆西行汽车的通过对。

对于数组的每一次迭代,如果东行计数器(汽车)是 0,则 num_east 计数器加一。对于每一辆西行汽车(1),我们将 num_east 的当前值加到 num_pass 变量上,因为所有的东行汽车都会经过这辆西行汽车。

文件名:CodilityProblem.java

输出

 
Number of passing cars: 5   

注意事项和边缘情况

溢出处理:在更改 num_pass 计数器的操作结构之后,代码包含一个溢出检查。这很重要,因为通过对的数量可能会急剧增加,以至于超出 1,000,000,000 的值。如果发生这种情况,函数将返回 -1,这将表明发生了溢出情况。

边界情况:它还能很好地处理以下边界情况:

  • 一个由 0 或 1 组成的数字数组,没有对,将返回 0,这是正确的结果。
  • 一个没有汽车或只有一辆汽车的数组也将等于 0,因为没有什么可以比较或配对。

效率和性能

因此,时间与输入大小成正比,对于更大的输入,给定的解决方案是最优的:时间复杂度为 O(N)。它只遍历整个数组一次,这使得它在输入数组大小方面非常高效。该解决方案的时间复杂度为 O(1),因为它使用了几个整数变量,因此也使得解决方案在内存方面非常高效。

结论

这是一个使用数组和高效算法解决 Codility Passing Cars 问题的良好实践。鉴于其允许精确实现单次扫描计数通过对的能力,所提供的解决方案可以被认为是最佳且相对稳定的。

因此,它能够处理大量的输入和其他未知值,同时密切关注其结果的正确性以及运行时间在设定的限制内。