AC113-将数组中的所有负数移动到数组最前端,非负数移动到数组最后端¶
类似快速排序的思想
代码实现¶
代码逻辑解析¶
- 初始化指针:
left指针从数组的起始位置(索引为 0)开始。-
right指针从数组的末尾位置(索引为n-1)开始。 -
循环条件:
-
当
left指针小于right指针时,继续执行循环。 -
移动指针:
- 内层第一个
while循环:如果left指针指向的元素是负数,则向右移动left指针。 -
内层第二个
while循环:如果right指针指向的元素是非负数,则向左移动right指针。 -
交换元素:
- 如果
left和right指针未相遇,说明left指针指向的是非负数,而right指针指向的是负数。 -
此时交换这两个元素的位置,使负数移到数组前面,非负数移到数组后面。
-
终止条件:
- 当
left指针大于或等于right指针时,说明所有负数已经移动到数组的前半部分,非负数已经移动到数组的后半部分。
时间复杂度分析¶
- 指针移动次数:
left指针从左向右移动,最多移动n次。right指针从右向左移动,最多移动n次。-
每个元素最多被访问一次,因此总的指针移动次数为
O(n)。 -
交换操作:
- 每次交换操作的时间复杂度为 O(1)。
- 总的交换次数不会超过
n/2。
综上,算法的时间复杂度为 O(n)。
空间复杂度分析¶
- 该算法只使用了常量级别的额外空间(如变量
left,right,temp),没有使用与输入规模相关的额外空间。 - 因此,空间复杂度为 O(1)。
较难理解部分的说明¶
为什么需要两个内层 while 循环?¶
- 第一个内层
while循环用于找到left指针指向的第一个非负数。 - 第二个内层
while循环用于找到right指针指向的第一个负数。 - 这样可以确保每次交换操作都符合要求:将负数移到前面,非负数移到后面。
图解说明¶
假设数组如下:
| Text Only | |
|---|---|
初始状态:
- 第一次循环:
left指针指向 3(非负数),right指针指向 -3(负数),交换两者。Text Only - 第二次循环:
left指针指向 -1(负数),无需交换;right指针指向 5(非负数),无需交换。 - 第三次循环:
left指针指向 2(非负数),right指针指向 -7(负数),交换两者。Text Only
最终结果:
| Text Only | |
|---|---|
延伸知识点¶
- 双指针法的应用:
- 双指针法常用于解决数组或链表的分区问题,例如快速排序中的分区操作、奇偶数分离等。
-
其核心思想是利用两个指针从两端向中间移动,逐步缩小搜索范围。
-
稳定性问题:
-
该算法不保证元素的相对顺序(即不稳定)。如果需要保持负数和非负数的相对顺序,可以使用其他方法(如创建辅助数组)。
-
扩展问题:
- 如果需要将数组分为三部分(如负数、零、正数),如何修改算法?
- 如果需要在原地完成且保持稳定性,如何设计算法?