问题描述
小R所在的国家有 𝑛n 个城市,每个城市的人口为 𝑎𝑖ai。如果某个城市的人口不超过其他任何一个城市人口的两倍,那么这个城市就被认为是稳定的。国家可以对部分城市实施政策,从而改变它们的人口数量。你的任务是帮助小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
思路分析
解题思路:
- 排序:首先,我们将城市的人口数组
a
进行排序。排序后,我们可以更容易地比较相邻城市的人口,从而判断是否满足稳定条件。 - 滑动窗口:使用滑动窗口的方法来找到最大的满足稳定条件的子数组长度。滑动窗口的左边界
left
和右边界right
初始化为0。我们逐渐移动右边界right
,对于每个新的right
位置,我们检查当前窗口内的城市是否满足稳定条件。 - 调整左边界:如果当前窗口不满足稳定条件(即
a[right] > 2 * a[left]
),则我们需要移动左边界left
,直到窗口内的城市再次满足稳定条件。 - 更新最大长度:每次移动右边界后,我们更新最大满足稳定条件的子数组长度
maxValidLen
。 - 计算修改次数:最后,最小修改次数等于总城市数
n
减去最大满足稳定条件的子数组长度maxValidLen
。
感悟
- 排序的妙用:排序是算法中常用的技巧,它可以简化很多问题的处理。在这个问题中,排序使得我们可以通过简单的相邻元素比较来检查条件,而无需复杂的嵌套循环或排序后的索引映射。
- 双指针技巧:双指针是处理数组和链表问题时的一种高效技巧。通过两个指针的协同移动,可以在一次遍历中解决很多问题,如寻找最长子序列、子数组等。
代码实现
import java.util.Arrays;
public class Main {
public static int solution(int n, int[] a) {
Arrays.sort(a);
int left = 0;
int maxValidLen = 0;
for (int right = 0; right < n; right++) {
while (left < n && a[right] > 2 * a[left]) {
left++;
}
maxValidLen = Math.max(maxValidLen, right - left + 1);
}
return n - maxValidLen;
}
public static void main(String[] args) {
System.out.println(solution(4, new int[]{1, 2, 3, 4}) == 1);
System.out.println(solution(5, new int[]{1, 10, 20, 30, 40}) == 2);
System.out.println(solution(3, new int[]{100, 50, 200}) == 1);
}
}