按下标奇偶性重排分两类:一是将原数组中奇下标元素集中前半、偶下标元素置后半(需保序,属空间优化变体);二是使最终数组满足偶下标位放偶数值、奇下标位放奇数值(如LeetCode 922),可用evenPos=0、oddPos=1双指针原地交换实现,时间O(n)、空间O(1)。

直接按数组下标奇偶性来重排元素,和按数值奇偶性分类是两回事。前者关注的是“位置”,后者关注的是“值”。你问的是前者如何在原地实现——也就是不额外申请数组,只靠交换完成重排。
核心目标要先分清
按下标奇偶性重排,典型场景有两种:
- 把原数组中所有“下标为奇数”的元素(即第2、4、6…个)集中到前半段,下标为偶数的放到后半段;
- 让最终数组满足:偶数下标位置放偶数值、奇数下标位置放奇数值(如 LeetCode 922),前提是输入中奇偶数数量相等。
两者逻辑不同,但都可原地完成。下面分别说明关键操作逻辑。
方法一:下标奇偶分离(前奇后偶)
目标是让所有原数组中索引为奇数的元素(如 arr[1], arr[3], arr[5]...)排在前面,索引为偶数的(arr[0], arr[2], arr[4]...)排在后面,且各自保持原始顺序。
这其实无法真正原地稳定完成——因为要保序,就必须腾挪空间。但可以模拟“逻辑原地”:
- 先算出奇数下标元素个数:
oddCount = (n + 1) / 2(若 n 为奇数,则下标 0,2,…,n−1 共 (n+1)/2 个偶数位;奇数位共 n/2 个); - 用双指针:
writeOdd = 0(写入奇数下标元素的位置),writeEven = oddCount(写入偶数下标元素的起始位置); - 单次遍历原数组下标
i,若i % 2 == 1,则把arr[i]放到arr[writeOdd++];否则放到arr[writeEven++]。
⚠️ 注意:这需要一个临时缓冲区或覆盖原数组——严格说不是“零额外空间”,但不新建同尺寸数组,属于空间优化的原地变体。
方法二:奇偶值与下标对齐(LeetCode 922 类型)
输入保证奇偶数各占一半,目标是让每个偶数下标 i 上放偶数值,每个奇数下标 i 上放奇数值。这是真正可原地交换的典型问题。
- 设两个指针:
evenPos = 0(指向下一个待填的偶数下标),oddPos = 1(指向下一个待填的奇数下标); - 遍历过程中,若
arr[evenPos]是奇数,就从oddPos开始往后找一个偶数值,交换; - 若
arr[oddPos]是偶数,就从evenPos开始往后找一个奇数值,交换; - 每次成功交换后,对应指针 += 2,继续推进。
该方法时间复杂度 O(n),空间 O(1),无需辅助数组,且交换过程天然保留在原数组内完成。
为什么不能混用“值奇偶”和“下标奇偶”逻辑?
例如数组 [2, 1, 4, 3]:
- 按值奇偶稳定重排 →
[1, 3, 2, 4](奇数在前,顺序不变); - 按下标奇偶提取 → 奇下标元素是
[1, 3],偶下标是[2, 4],合并为[1, 3, 2, 4]—— 此时结果巧合相同,但逻辑完全不同; - 若原数组是
[5, 8, 1, 6],下标奇偶提取得[8, 6, 5, 1],而值奇偶重排是[5, 1, 8, 6],结果明显不同。
所以实现前必须明确:你要重排的依据是“下标位置”,还是“元素数值”,二者策略不可互换。










