小R的城市稳定性挑战 | 豆包MarsCode AI刷题

221 阅读6分钟

小R的城市稳定性挑战 - MarsCode

问题描述

小R所在的国家有 nn 个城市,每个城市的人口为 aiai​。如果某个城市的人口不超过其他任何一个城市人口的两倍,那么这个城市就被认为是稳定的。国家可以对部分城市实施政策,从而改变它们的人口数量。你的任务是帮助小R找到最少需要对多少个城市进行人口修改,才能使所有城市都变得稳定。

例如:对于城市人口为 [1, 2, 3, 4] 的国家,最少需要对1个城市执行政策,才能使所有城市稳定。


测试样例

样例1:

输入:n = 4 ,a = [1, 2, 3, 4]
输出:1

样例2:

输入:n = 5 ,a = [1, 10, 20, 30, 40]
输出:2

样例3:

输入:n = 3 ,a = [100, 50, 200]
输出:1

我们需要确保所有城市的人口都符合“稳定”的条件:对于任意城市 iijj,如果城市 ii 和城市 jj 的人口分别为 aia_iaja_j,则必须满足:

ai≤2⋅aj且aj≤2⋅aia_i \leq 2 \cdot a_j \quad \text{且} \quad a_j \leq 2 \cdot a_iai​≤2⋅aj​且aj​≤2⋅ai​

换句话说,任何城市的人口都不能是其他任何城市人口的两倍以上。我们需要通过最少的修改来满足这个条件。

思路分析:

  1. 城市排序:首先,我们对城市人口进行排序。这样就可以确保对于任意城市 iijj,如果 i<ji < j,那么 aiaja_i \leq a_j,便于检查和修改。
  2. 滑动窗口:对排序后的城市数组使用滑动窗口的方法来寻找最大符合稳定条件的子数组。具体来说,我们将考虑每一个城市作为窗口的起点,然后找到这个城市和之后的其他城市人口差异符合条件的最长子数组。
  3. 最小修改数:找到最大稳定的子数组之后,所有不在这个子数组中的城市就是需要进行修改的城市。所以,我们的目标是最大化这个稳定的子数组的长度,最少修改的城市数就是总城市数减去稳定子数组的长度。

解决方案:

  1. 对人口数组进行排序。
  2. 使用双指针方法遍历,维护一个窗口来寻找最大稳定的子数组。
  3. 计算最小修改数:即 n - max_valid_subarray_length

代码实现:

python
复制代码
def solution(n, a):
    a.sort()  # 将人口数组排序
    left = 0  # 滑动窗口的左端
    max_valid_len = 0  # 记录最大符合稳定条件的子数组长度
    
    # 滑动窗口法
    for right in range(n):
        # 当窗口内的子数组不符合条件时,左指针右移,缩小窗口
        while a[right] > 2 * a[left]:
            left += 1
        # 更新最大稳定子数组长度
        max_valid_len = max(max_valid_len, right - left + 1)
    
    # 最小修改次数 = 总城市数 - 最大稳定子数组长度
    return n - max_valid_len

解释:

  1. 排序:我们首先对人口数组 a 进行升序排序,使得对于任意 i<ji < j,我们有 aiaja_i \leq a_j。这使得我们只需要考虑一个方向的比较(从小到大),避免了多余的判断。

  2. 双指针(滑动窗口)

    • left 是窗口的左边界,right 是窗口的右边界。初始时,leftright 都指向第一个城市。
    • 对于每一个右指针的位置,我们检查当前窗口(从 leftright)中的所有城市是否满足稳定条件。也就是说,我们检查是否有 a[right]2×a[left]a[right] \leq 2 \times a[left]。如果不满足,则通过移动左指针来收缩窗口,直到满足条件。
    • 每次扩展右指针时,更新最大合法子数组的长度。
  3. 最小修改数:最终,最小修改数等于总城市数 n 减去最大合法子数组的长度。

示例测试:

  1. 样例1

    python
    复制代码
    print(solution(4, [1, 2, 3, 4]))  # 输出 1
    
    • 排序后的数组为 [1, 2, 3, 4],最大的稳定子数组长度为 4(整个数组),不需要修改。
  2. 样例2

    python
    复制代码
    print(solution(5, [1, 10, 20, 30, 40]))  # 输出 2
    
    • 排序后的数组为 [1, 10, 20, 30, 40],最大的稳定子数组是 [10, 20],需要修改 140,所以最小修改次数为 2。
  3. 样例3

    python
    复制代码
    print(solution(3, [100, 50, 200]))  # 输出 1
    
    • 排序后的数组为 [50, 100, 200],最大的稳定子数组是 [50, 100],需要修改 200,所以最小修改次数为 1。

时间复杂度:

  • 排序O(nlogn)O(n \log n),排序城市人口。
  • 滑动窗口O(n)O(n),双指针方法遍历一次数组。 因此,总的时间复杂度是 O(nlogn)O(n \log n),适合较大的输入规模。

空间复杂度:

  • O(1)O(1),仅使用了常数空间来存储指针和结果。

这是一种高效的解法,通过排序和滑动窗口使得问题能够在较短时间内解决。

这道题目要求我们通过最少的人口修改,使得所有城市满足“稳定”条件,即任何一个城市的人口不超过其他城市人口的两倍。为了解决这个问题,我们需要找到一个高效的方法来判断哪些城市满足条件,并最小化修改的城市数。

思路分析

  1. 稳定条件:城市 ii 和城市 jj 的人口满足条件当且仅当 ai2aja_i \leq 2 \cdot a_jaj2aia_j \leq 2 \cdot a_i。因此,城市之间的关系是相对的,我们需要通过排序来简化判断。
  2. 排序:首先对城市人口数组进行排序,确保对于任何两个城市 iijj,如果 i<ji < j,则 aiaja_i \leq a_j。这使得我们只需检查从小到大的城市人口关系。
  3. 滑动窗口:使用双指针(滑动窗口)技术来寻找最长的符合稳定条件的子数组。right 指针遍历数组,left 指针在不满足条件时移动。每次右指针扩展时,我们判断当前窗口内的所有城市是否满足稳定条件,若满足则扩大窗口,否则缩小窗口。
  4. 最小修改数:最大稳定子数组的长度就是不需要修改的人口数,最小修改数则为总城市数减去最大稳定子数组的长度。

时间复杂度

  • 排序操作需要 O(nlogn)O(n \log n),滑动窗口操作是 O(n)O(n),因此总体时间复杂度是 O(nlogn)O(n \log n)

通过这种方法,能够高效地找到最少修改数,适应较大的输入规模。