10、奇数放到偶数前面

本文介绍两种算法实现在数组中将奇数与偶数分开。第一种通过双指针技术在原地完成奇偶分离;第二种保持相对顺序不变,采用插入排序思路或使用额外空间分别收集奇偶数再合并。

题目:

题目1:输入一个整数数组,实现函数使得数组奇数位于数组前半部分,所有偶数位于数组后边部分。

题目2:输入一个整数数组,实现函数使得数组奇数位于数组前半部分,所有偶数位于数组后边部分。并保证原数组的相对位置不变。

解法

题目1:

    1、利用两个指针left,right。分别从左和从右寻找奇数偶数进行交换即可。

代码如下:

    void reOrderArray(vector<int> &array) {
        if(array.empty()||array.size()==0)
            return;
        int left = 0;
        int right = n-1;
        while(left<right)
        {
            while(left<n && array[left]%2==1)
                left++;
            while(left<n && array[right]%2==0)
                right--;
            if(left<right)
                swap(array[left],array[right]);
        }
    }

题目2:

    1、为保证相对位置的有序,利用插排思想进行相邻位置的比较。时间复杂度o(n^2)

    2、利用辅助空间,例如两个vector,遍历数组一次,分别取出奇数偶数。在一起合并后返回.时间o(n) 空间0(n)

代码1如下

    void reOrderArray(vector<int> &array) {  //类似插排
        if(array.empty())
            return ;
        int first;//存放第一个奇点在原数组的位置
        int index=-1;//存放 调整好的最后一个奇点的位置
        //寻找第一个奇点
        int n = array.size();
        for(int i = 0;i<n;i++)
        {
            if(array[i]%2 == 1)
            {
                int temp = array[i];
                first = i ; 
                for(int j = first ;j>index+1;j--)
                    array[j] = array[j-1];
                array[index+1] = temp;
                index++;
                break;
            }
        }
        for(int i = first+1;i<n;i++) //寻找后面的奇点
        {
            if(array[i] % 2 ==1)
            {
                int temp = array[i];
                int temp_index = i;
                for(int j = temp_index;j>index+1;j--)
                    array[j] = array[j-1];
                array[index+1] = temp;
                index++;
            }
        }
    }

代码2如下

    void reOrderArray(vector<int> &array) {
        if(array.empty()||array.size()==0)
            return;
        vector<int> ji;
        vector<int> ou;
        for(int i =0;i<array.size();i++)
        {
            if(array[i]%2==0)
                ou.push_back(array[i]);
            else
                ji.push_back(array[i]);
        }
        array.clear();
        for(int i = 0;i<ji.size();i++)
            array.push_back(ji[i]);
        for(int i = 0;i<ou.size();i++)
            array.push_back(ou[i]);
    }


### 实现调整单链表结构使偶数节点位于奇数节点前的算法 为了实现这一目标,可以利用双指针技术,在不改变原始节点顺序的情况下重新排列链表。以下是具体方法: #### 方法概述 通过维护两个子链表——一个用于存储偶数值节点,另一个用于存储奇数值节点。遍历整个链表时,将当前节点按其值分类并连接到对应的子链表上。最终将这两个子链表合并。 --- #### Python代码实现 ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def oddEvenList(head): if not head or not head.next: return head # 初始化偶数奇数链表的头部及其辅助指针 even_head = None odd_head = None even_tail = None odd_tail = None current = head index = 1 # 节点索引号 while current: if (index % 2 == 0): # 偶数位置节点 if not even_head: even_head = current even_tail = even_head else: even_tail.next = current even_tail = even_tail.next else: # 奇数位置节点 if not odd_head: odd_head = current odd_tail = odd_head else: odd_tail.next = current odd_tail = odd_tail.next # 移动到下一个节点,并更新索引 temp = current.next current.next = None # 断开原链接以防成环 current = temp index += 1 # 合并偶数链表和奇数链表 if even_tail and odd_head: even_tail.next = odd_head return even_head elif odd_head: # 如果只有奇数节点 return odd_head else: # 链表为空或者全是偶数节点 return even_head ``` 上述代码实现了基于节点编号的分离逻辑[^1]。如果需要基于节点值(而非编号)进行区分,则需稍作修改如下所示。 --- #### 修改后的Python代码(基于节点值) ```python def separateByValue(head): if not head or not head.next: return head # 创建虚拟头节点以便于处理边界情况 dummy_even = ListNode(-1) dummy_odd = ListNode(-1) even_ptr = dummy_even odd_ptr = dummy_odd current = head while current: if current.val % 2 == 0: # 当前节点值为偶数 even_ptr.next = current even_ptr = even_ptr.next else: # 当前节点值为奇数 odd_ptr.next = current odd_ptr = odd_ptr.next # 更新current指向下一节点 temp = current.next current.next = None # 切断原有链接防止循环引用 current = temp # 连接偶数部分和奇数部分 even_ptr.next = dummy_odd.next return dummy_even.next ``` 此版本依据节点的实际值判断是否属于偶数奇数组合[^3]。 --- #### 复杂度分析 - **时间复杂度**: O(n),其中 n 是链表长度。只需一次遍历来完成重排。 - **空间复杂度**: O(1),除了几个额外变量外无需其他内存分配。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值