力扣 922. 按奇偶排序数组 II :双指针原地交换

目录

题目解析

算法思路:双指针原地交换

关键步骤:

正确性证明:

示例详解

复杂度分析

对比其他解法

总结


题目解析

题目要求将非负整数数组重新排列,使得所有偶数元素位于偶数索引(0, 2, 4, ...),所有奇数元素位于奇数索引(1, 3, 5, ...)。题目保证至少存在一个有效解,且答案不唯一。

示例输入输出

  • 输入:nums = [4,2,5,7]

  • 输出:[4,5,2,7](或其他合法排列)


算法思路:双指针原地交换

核心思想是通过双指针分别跟踪偶数索引和奇数索引,逐步将元素调整到正确的位置。

关键步骤:
  1. 初始化双指针

    • even 指针从 0 开始,步长为 2,用于寻找偶数索引处的奇数元素。

    • odd 指针从 1 开始,步长为 2,用于寻找奇数索引处的偶数元素。

  2. 循环处理

    • 若 even 指向的元素是偶数,说明当前位置正确,even 后移 2 步。

    • 若 odd 指向的元素是奇数,说明当前位置正确,odd 后移 2 步。

    • 否则,交换 even 和 odd 指向的元素,这样两个位置的元素均满足条件。

  3. 终止条件

    • 当任意指针超出数组长度时,所有元素已正确排列。

正确性证明:

每次交换操作至少修复两个位置的错误(一个偶数的位置和一个奇数的位置),由于题目保证输入有解,算法最终会将所有元素归位。

/**
 * @param {number[]} nums
 * @return {number[]}
 */
var sortArrayByParityII = function(nums) {
    let even = 0; // 偶数索引
    let odd = 1; // 奇数索引
    while (even < nums.length && odd < nums.length) {
        if (nums[even] % 2 === 0) { // 如果偶数索引处的数字是偶数
            even += 2; // 移动到下一个偶数索引
        } else if (nums[odd] % 2 === 1) { // 如果奇数索引处的数字是奇数
            odd += 2; // 移动到下一个奇数索引
        } else { // 如果偶数索引处的数字是奇数且奇数索引处的数字是偶数
            [nums[even], nums[odd]] = [nums[odd], nums[even]]; // 交换它们
        }
    }
    return nums; // 返回排序后的数组
};

console.log(sortArrayByParityII([4, 2, 5, 7]));

示例详解

以输入 nums = [4,2,5,7] 为例:

  1. 初始状态

    • even = 0odd = 1

    • 检查 nums[0] = 4(偶数),even 移动到 2

  2. 第二轮循环

    • nums[2] = 5(奇数),检查 odd = 1 处的 nums[1] = 2(偶数)。

    • 交换两者,数组变为 [4,5,2,7]

  3. 指针更新

    • even 移动到 4,超出数组长度,循环终止。

最终结果为 [4,5,2,7],所有偶数位于偶数索引,奇数位于奇数索引。


复杂度分析

  • 时间复杂度:O(n),每个元素最多被访问一次。

  • 空间复杂度:O(1),原地交换,仅使用常数空间。


对比其他解法

  1. 额外空间法

    • 分别收集偶数和奇数,依次填充到偶数索引和奇数索引。

    • 时间复杂度 O(n),但空间复杂度 O(n)。

  2. 两次遍历法

    • 第一次处理偶数,第二次处理奇数,但实现较为繁琐。

当前的双指针法在时间和空间上均最优,适合大数据量的场景。


总结

通过双指针一次遍历,原地交换元素,该算法高效且优雅地解决了奇偶排序问题。理解双指针移动的条件和交换的动机是掌握此算法的关键。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端 贾公子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值