目录
问题描述
教练使用整数数组 actions
记录一系列核心肌群训练项目编号。为增强训练趣味性,需要将所有奇数编号训练项目调整至偶数编号训练项目之前。请将调整后的训练项目编号以 数组 形式返回。
输入:
actions
:整数数组,表示不同位置的训练项目编号。limit
:整数,表示训练项目的视野范围,即滑动窗口的大小。
输出:
- 返回一个数组,其中所有奇数编号训练项目位于偶数编号训练项目之前,且相对顺序保持不变。
示例 1:
输入:
actions = [1,2,3,4,5]
输出:
[1,3,5,2,4]
解释:
将所有奇数编号训练项目 [1, 3, 5] 移动到偶数编号训练项目 [2, 4] 之前,保持相对顺序不变。
提示:
0 <= actions.length <= 50000
0 <= actions[i] <= 10000
原题链接:
示例
示例 1:
输入:
actions = [1,2,3,4,5]
输出:
[1,3,5,2,4]
解释:
在上述示例中,所有奇数编号训练项目 [1, 3, 5]
被移动到偶数编号训练项目 [2, 4]
之前,且相对顺序保持不变。
思路解析
本题要求将数组 actions
中所有奇数编号的训练项目移动到偶数编号训练项目之前,同时保持奇数和偶数各自的相对顺序。由于需要保持相对顺序,我们可以采用以下几种方法来解决该问题:
方法一:使用额外空间
核心思路
遍历原数组,将奇数编号和偶数编号分别存储到两个新的数组中,最后将奇数数组和偶数数组合并即可。该方法简单直观,能够有效地保持奇数和偶数的相对顺序。
详细步骤
-
初始化:
- 创建两个空的列表
odds
和evens
分别用于存储奇数编号和偶数编号的训练项目。
- 创建两个空的列表
-
遍历数组:
- 对于数组中的每个元素
num
:- 如果
num
是奇数,则添加到odds
列表中。 - 如果
num
是偶数,则添加到evens
列表中。
- 如果
- 对于数组中的每个元素
-
合并结果:
- 将
odds
列表和evens
列表合并为一个新的列表result
。
- 将
-
返回结果:
- 返回合并后的
result
列表。
- 返回合并后的
示例分析
以示例 1 为例:
actions = [1,2,3,4,5]
-
遍历数组:
1
是奇数,添加到odds
→odds = [1]
2
是偶数,添加到evens
→evens = [2]
3
是奇数,添加到odds
→odds = [1, 3]
4
是偶数,添加到evens
→evens = [2, 4]
5
是奇数,添加到odds
→odds = [1, 3, 5]
-
合并结果:
result = odds + evens = [1, 3, 5, 2, 4]
方法二:双指针法(原地交换)
核心思路
使用双指针法在原数组上进行操作,分别指向数组的起始和末尾。通过交换奇数和偶数的位置,将所有奇数移动到数组的前半部分,偶数移动到后半部分。该方法节省了空间,但可能会破坏奇数和偶数的相对顺序。
详细步骤
-
初始化指针:
left
指针初始化为数组起始位置0
。right
指针初始化为数组末尾位置n-1
。
-
遍历数组:
- 当
left
小于right
时:- 如果
actions[left]
是奇数,移动left
指针向右。 - 如果
actions[left]
是偶数,并且actions[right]
是奇数,则交换actions[left]
和actions[right]
,然后移动left
和right
指针。 - 如果
actions[right]
不是奇数,则仅移动right
指针。
- 如果
- 当
-
终止条件:
- 当
left
不再小于right
时,结束遍历。
- 当
-
返回结果:
- 返回调整后的
actions
数组。
- 返回调整后的
注意事项
- 该方法可能会破坏奇数和偶数的相对顺序。如果题目要求保持相对顺序,应采用方法一。
示例分析
以示例 1 为例:
actions = [1,2,3,4,5]
left = 0, right = 4
-
第一次循环:
actions[left] = 1
是奇数,left
移动到1
.
-
第二次循环:
actions[left] = 2
是偶数,actions[right] = 5
是奇数,交换2
和5
。- 数组变为
[1,5,3,4,2]
left
移动到2
,right
移动到3
.
-
第三次循环:
actions[left] = 3
是奇数,left
移动到3
.
-
结束遍历。
-
最终数组为
[1,5,3,4,2]
注意:该方法不保持相对顺序,但符合题意要求。
方法三:插入法(保持相对顺序)
核心思路
遍历数组,将奇数元素插入到结果数组的前面,同时保持其相对顺序。该方法需要额外的空间,但能够保持奇数和偶数的相对顺序。
详细步骤
-
初始化:
- 创建一个空的结果列表
result
。
- 创建一个空的结果列表
-
遍历数组:
- 对于数组中的每个元素
num
:- 如果
num
是奇数,添加到result
列表的末尾。
- 如果
- 对于数组中的每个元素
-
再次遍历数组:
- 对于数组中的每个元素
num
:- 如果
num
是偶数,添加到result
列表的末尾。
- 如果
- 对于数组中的每个元素
-
返回结果:
- 返回合并后的
result
列表。
- 返回合并后的
示例分析
以示例 1 为例:
actions = [1,2,3,4,5]
-
遍历数组,添加奇数:
1
是奇数,result = [1]
2
是偶数,跳过3
是奇数,result = [1, 3]
4
是偶数,跳过5
是奇数,result = [1, 3, 5]
-
再次遍历数组,添加偶数:
1
是奇数,跳过2
是偶数,result = [1, 3, 5, 2]
3
是奇数,跳过4
是偶数,result = [1, 3, 5, 2, 4]
5
是奇数,跳过
-
最终结果为
[1, 3, 5, 2, 4]
代码实现
Python 实现(方法一:使用额外空间)
from typing import List
class Solution:
def rearrangeActions(self, actions: List[int]) -> List[int]:
"""
方法一:使用额外空间
分别收集奇数和偶数,最后合并。
:param actions: List[int] - 训练项目编号数组
:return: List[int] - 调整后的训练项目编号数组
"""
odds = []
evens = []
for num in actions:
if num % 2 != 0:
odds.append(num)
else:
evens.append(num)
return odds + evens
Python 实现(方法二:双指针法)
from typing import List
class Solution:
def rearrangeActions(self, actions: List[int]) -> List[int]:
"""
方法二:双指针法(原地交换)
将所有偶数移到数组末尾,奇数保留在前面。可能会破坏相对顺序。
:param actions: List[int] - 训练项目编号数组
:return: List[int] - 调整后的训练项目编号数组
"""
left = 0
right = len(actions) - 1
while left < right:
if actions[left] % 2 != 0:
left += 1
elif actions[right] % 2 == 0:
right -= 1
else:
actions[left], actions[right] = actions[right], actions[left]
left += 1
right -= 1
return actions
Python 实现(方法三:插入法)
from typing import List
class Solution:
def rearrangeActions(self, actions: List[int]) -> List[int]:
"""
方法三:插入法(保持相对顺序)
首先收集所有奇数,然后收集所有偶数,保持相对顺序不变。
:param actions: List[int] - 训练项目编号数组
:return: List[int] - 调整后的训练项目编号数组
"""
result = []
for num in actions:
if num % 2 != 0