[s]O-21 调整数组顺序使奇数在偶数之前(python实现与升级版腾讯面试题)
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有奇数位于数组的前半部分,所有偶数位于数组的后半部分。
输入:nums = [1,2,3,4]
输出:[1,3,2,4]
注:[3,1,2,4] 也是正确的答案之一。
方法解决/代码
Method1 双指针
参考:link
考虑定义双指针 i, j分列数组左右两端,循环执行:
- 指针 i从左向右寻找偶数;
- 指针 j 从右向左寻找奇数;
将偶数 nums[i] 和 奇数 nums[j] 交换。
可始终保证: 指针i左边都是奇数,指针j右边都是偶数 。
(1)初始化: i, j双指针,分别指向数组nums 左右两端;
(2)循环交换: 当 i = j时跳出;
指针 i 遇到奇数则执行 i = i + 1 跳过,直到找到偶数;
指针 j 遇到偶数则执行 j = j - 1 跳过,直到找到奇数;
交换 nums[i] 和 nums[j] 值;
(3)返回值: 返回已修改的nums 数组
解释:
内层的保证i<j必须有
在左右两边不断地往前往后循环时,也要保证i<j,防止在内层经过i+=1和j-=1后出现了i==j的时候,依然交换了位置,然后导致上一轮换过的位置又换回来了。
可以根据【1,2,3,4】这个例子分布调试理解
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
i,j=0,len(nums)-1
while i<j:
while i<j and nums[i]&1==1: i+=1
while i<j and nums[j]&1==0: j-=1
nums[i],nums[j]=nums[j],nums[i]
return nums
Method2(一次循环)
循环一变,不断的把奇数往前放。
(1)定义指针odd 和 i
(2)i 的作用是向前搜索奇数位置,odd的作用是指向下一个奇数应当存放的位置
(3)i 向前移动,当它搜索到奇数时,将它和nums[odd] 交换,此时 odd向前移动一个位置 .
(4)重复上述操作,直到i指向数组末尾
class Solution:
def exchange(self, nums: List[int]) -> List[int]:
odd=0
for i in range(len(nums)):
if nums[i]&1==1:
nums[i],nums[odd]=nums[odd],nums[i]
odd+=1
return nums
升级版问题(顺序限制)与代码
参考:java版本解答
小Q最近遇到了一个难题:把一个字符串的大写字母放到字符串的后面,各个字符的相对位置不变,且不能申请额外的空间。 你能帮帮小Q吗?
这个题目的简单版本与上面类似:即把所有小写字母放在前面,大写字母放在后面。
可以直接根据上面2个简单版本写出如下2个方法:
def Q_q_exchange(self,words):
words=list(words)
i,j=0,len(words)-1
while(i<j):
while(i<j)and words[i]>='a'and words[i]<='z': i+=1
while(i<j)and words[j]>='A'and words[j]<='Z': j-=1
words[i],words[j]=words[j],words[i]
return ''.join(words)
small:理解为下一个小写字母在的位置
i:遍历寻找小写字母把他放在前面
def Q_q_exchange2(self,words):
words=list(words)
small=0
for i in range(len(words)):
if (words[i]>='a'and words[i]<='z'):
words[i],words[small]=words[small],words[i]
small+=1
return ''.join(words)
这样示例2个方法结果均如下:
inout: aABbcdCD
output: adcbBACD
满足小写在前大写在后但是字母顺序变了。
本题限制:各个字符的相对位置不变
分析:
我们可以这样,我们用一个small指针来指向小写字母,i指针来遍历,当i指针遇到小写字母时,有如下几种情况:
- 大写字母还没出现呢,直接跳过
- 前面有大写字母出现了 :这时分两种情况
small在i前面small相邻一个(i-bid==1),这种情况直接交换small不在index前面相邻位置,说明small和index之前有好几个大写字母,如果直接交换,必然不满足题目要求,这种场景可以用插入排序的思想,先保存原先i指向的值value,然后让small到(i-1)之间整体往后移动一个位置,然后把value插入到small的位置。
#根据方法2改编的
def Q_q_exchange_3(self, words):
words = list(words)
small = 0
for i in range(len(words)):
if (words[i] >= 'a' and words[i] <= 'z'):
if(small<i):
if(i-small==1):
words[i], words[small] = words[small], words[i]
small=i
else:
value=words[i]
while(i>small):
words[i]=words[i-1]
i-=1
words[small]=value
small+=1
else:
small+=1
return ''.join(words)
此时结果
inout: aABbcdCD
output: abcdABCD
----------2021/01/04 举一反三,双指针,保持顺序-----------