数组划分

本文介绍了一个在原地使用O(n)时间复杂度划分整数数组的算法案例,该算法将数组中小于给定值k的元素移至左侧,大于等于k的元素移至右侧,并返回第一个大于等于k的元素的位置。

给出一个整数数组nums和一个整数k。划分数组(即移动数组nums中的元素),使得:

  • 所有小于k的元素移到左边
  • 所有大于等于k的元素移到右边

返回数组划分的位置,即数组中第一个位置i,满足nums[i]大于等于k。

样例
给出数组nums=[3,2,2,1]和 k=2,返回 1

注意
你应该真正的划分数组nums,而不仅仅只是计算比k小的整数数,如果数组nums中的所有元素都比k小,则返回nums.length。

挑战
要求在原地使用O(n)的时间复杂度来划分数组。


class Solution {
public:
    int partitionArray(vector<int> &nums, int k) {
        if(nums.empty()||nums.size()==0)
             return 0;
        int i=0, n=nums.size()-1;
        while(true) 
        {
            while(i<n&&nums[n]>=k)
            {
                n--;
            }
            while(i<n&&nums[i]<k) 
            {
                i++;
            }
            if(i==n) 
                break;
            swap(i,n,nums);
        }
        if(i==0 && nums[i]>=k) 
              return n;
        if(n==nums.size()-1 && nums[i]<k) 
              return n+1;
        return n+1;
    }
    void swap(int i,int n,vector<int> &nums)
    {
         int temp=nums[i];
         nums[i]=nums[n];
         nums[n]=temp;
    }
};


数组划分(Array Partitioning)是一个常见的算法问题,通常出现在排序、分治、快速选择等算法中。在不同的上下文中,“数组划分”可能有不同的含义: --- ## ✅ 常见的“数组划分”问题类型 1. **基于某个值 pivot 的划分**(如快排中的 partition 操作): - 将小于等于 pivot 的元素放在左边,大于的放在右边。 2. **将数组划分为两个部分,使得两部分的和尽可能接近**。 3. **将数组划分为 k 个子数组,满足某些条件**。 下面我将以最常见的第一种情况为例:**基于 pivot 的数组划分**,使用 C++ 实现一个经典的 **Lomuto 分区方案** 和 **Hoare 分区方案**。 --- ## 🧱 Lomuto 分区实现(以最后一个元素为 pivot) ```cpp #include <bits/stdc++.h> using namespace std; int lomutoPartition(vector<int>& arr, int left, int right) { int pivot = arr[right]; // 选取最右端作为 pivot int i = left - 1; // i 是小于 pivot 的边界指针 for (int j = left; j < right; ++j) { if (arr[j] <= pivot) { ++i; swap(arr[i], arr[j]); } } swap(arr[i + 1], arr[right]); // 把 pivot 放到正确的位置上 return i + 1; // 返回 pivot 的位置 } int main() { vector<int> arr = {10, 80, 30, 90, 40, 50, 70}; int n = arr.size(); int pivotIndex = lomutoPartition(arr, 0, n - 1); cout << "Pivot value: " << arr[pivotIndex] << endl; cout << "Partitioned array: "; for (int x : arr) cout << x << " "; cout << endl; return 0; } ``` ### 🔍 解释: - 时间复杂度:O(n) - 空间复杂度:O(1) - `i` 表示小于等于 pivot 的区域的末尾。 - 最后把 pivot(原数组最后一个元素)放到 `i+1` 的位置。 --- ## 🧱 Hoare 分区实现(双向扫描) ```cpp #include <bits/stdc++.h> using namespace std; int hoarePartition(vector<int>& arr, int left, int right) { int pivot = arr[left]; int i = left - 1, j = right + 1; while (true) { do { i++; } while (arr[i] < pivot); // 找比 pivot 大或等于的 do { j--; } while (arr[j] > pivot); // 找比 pivot 小或等于的 if (i >= j) return j; // 分界点 swap(arr[i], arr[j]); } } int main() { vector<int> arr = {10, 80, 30, 90, 40, 50, 70}; int n = arr.size(); int p = hoarePartition(arr, 0, n - 1); cout << "Partition index: " << p << endl; cout << "Partitioned array: "; for (int x : arr) cout << x << " "; cout << endl; return 0; } ``` ### 🔍 解释: - 更高效,交换次数更少。 - 使用双指针从两端向中间扫描。 - 当 `i >= j` 时返回 `j`,作为下一次递归的边界。 --- ## 📌 示例输入输出(任选一种) 输入: ```cpp {10, 80, 30, 90, 40, 50, 70} ``` 输出(Lomuto): ``` Pivot value: 70 Partitioned array: 10 30 40 50 70 90 80 ``` 输出(Hoare): ``` Partition index: 4 Partitioned array: 10 30 40 50 70 90 80 ``` --- ##
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值