[s]O-21 调整数组顺序使奇数在偶数之前(python实现与升级版腾讯面试题)

[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 举一反三,双指针,保持顺序-----------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值