当前位置: 首页 > news >正文

算法——分治

分治即分而治之,将一整个大问题分解成若干个小问题来解决。


一.颜色分类

来看题目(出自力扣):

题目很简单,让我们将一个数组中乱序的颜色排列成红、白、蓝的正确序列

因为题目中是用数字来代替颜色,因此题目要求不能使用排序函数。

那么我们如何来解决这个问题呢???

根据分治思想,题目要求我们将颜色分为三块,也就是说我们要管理三块区域,因此我们是否能通过去遍历数组,然后将元素放在其应在的区域呢???

如下图所示,我们可以使用三指针,其中 i 指针去遍历数组,如果 i 下标元素为0,就将其放在left维护的左边区域,如果为2,就将其放在right维护的右边区域,而剩余的1,都将会被集中在中间区域

值得注意的是,i 下标是从左侧开始去遍历数组的,所以 i 下标左侧的区间一定是排好序的 0 和  1,而当 i 右侧的区域则是未排序的一段数据和排好的 2

这意味着当 i 与 left 交换一次数据之后,可以直接++,但是当 i 与 right 交换一次数据之后,得到的可能是0,所以 i 就不能++,必须重新进行一次判断

    void sortColors(vector<int>& nums) {
        int left = -1,right = nums.size(),i = 0;
        while(i < right)
        {
            if(nums[i] == 0)
                swap(nums[++left],nums[i++]);
            else if(nums[i] == 2)
                swap(nums[--right],nums[i]);
            else
                i++;
        }
    }

二.快速排序

上述分治思想,貌似和快速排序的思想很相似,相对的,我们也可以用分治的思想来优化快排如果快速排序的数组中有很多重复元素,甚至是全是重复元素, 那快速排序的效率就会及其低下

因此,我们希望优化一下快速排序,那么就可以通过上述三指针的思想,确定数组中的一个基准元素key,一次排序后将数组分为三块,左边块全是小于key,中间块全是等于key,右边块全是大于key,这样就能保证相同的元素不会继续参与排序

其中key的选择,我们采用在排序数组中随机选择的方式,具体优化代码如下:

    void quickSort(vector<int>& nums,int begin,int end)
    {
        if(begin >= end) return; 
        int left = begin - 1,right = end + 1;

        int key = nums[begin + (rand() % (end - begin + 1))];
        int  i = begin;
        while(i < right)
        {
            if(key < nums[i])
                swap(nums[--right],nums[i]);
            else if(key > nums[i])
                swap(nums[++left],nums[i++]);
            else
                i++;
        }
        mySort(nums,begin,left);
        mySort(nums,right,end);
    }
    vector<int> sortArray(vector<int>& nums) 
    {
        srand(time(NULL));
        quickSort(nums,0,nums.size() - 1);
        return nums;
    }

三.交易逆序对的总数

来看题目(出自力扣):

题目很好理解,就是让我们统计一个数组中,前一个数比后一个数大的数对有多少个。 

 很显然,这道题可以直接通过两层for循环遍历数组来暴力求解,但是我们希望用时间复杂度更加优秀的解法,该怎么解这道题呢???

本题,我们可以采用分治 + 归并的思想来优化时间复杂度。

首先我们需要复习一下归并排序的原理:将一个数组分成两块,分别将两块子数组内的元素进行排序,最后再将两块数组合在一起整体排序,如此递归下去,就能得到一个时间复杂度为O(N*logN)的排序效率

那么本题为什么可以使用归并排序呢??? 

我们用题目的示例来做解释,将数组分为如下两块,能够看出,一开始两个子数组还是乱序,现在我们来统计两个子数组中的逆序对,分别是(9,7)和(5,4),统计完之后,这两个子数组就可以分别完成内部排序。

有没有发现其中的奥秘,我们将子数组分别排序之后,并不会影响相较于两个子数组中的两个元素的相对位置,比如7和6的前后位置是相对不变的,此时再将两个子数组进行整体排序,因为归并排序将两个子数组合并时,是分别去比较两个数字的大小的,所以我们就可以在这时得到逆序对

 得此结论,我们就可以在归并排序的过程中,去统计逆序对的个数。

class Solution {
    int arr[50001];
public:
    int mergeSort(vector<int>& record, int left,int right)
    {
        if(left >= right) return 0;
        int mid = (left + right) >> 1;
        int ret = 0;
        ret += mergeSort(record,left,mid);
        ret += mergeSort(record,mid + 1,right);
        int cur1 = left,cur2 = mid + 1;
        int i = 0;
        while(cur1 <= mid && cur2 <= right)
        {
            if(record[cur1] > record[cur2])
            {
                ret += mid - cur1 + 1;
                arr[i++] = record[cur2++];

            }
            else
                arr[i++] = record[cur1++];
        }
        while(cur1 <= mid)
            arr[i++] = record[cur1++];
        while(cur2 <= right)
            arr[i++] = record[cur2++];
        for(int j = left; j <= right;j++)
            record[j] = arr[j - left];
        return ret;
    }

    int reversePairs(vector<int>& record) {
        return mergeSort(record,0,record.size() - 1);
    }
};

由于快排和归并排序都表现出分治的思想,所以在分治算法中二者是常客。

相关文章:

  • Java从根上理解 ConcurrentHashMap:缓存机制与性能优化
  • 欧几里得算法
  • 计算机视觉 |解锁视频理解三剑客——SlowFast
  • 基于云函数的自习室预约微信小程序+LW示例参考
  • 服务器为什么会禁止 Ping?服务器禁止 Ping 的好处
  • 【项目管理工具推荐二】【信息化系统需求管理工具万字指南:从需求收集到落地全链路拆解】
  • 如何在Android中实现多线程
  • 蓝桥杯备考1
  • C#模式匹配详解
  • 【无标题】Day 4 CSS盒子模型
  • C++ 设计模式 十:享元模式 (读书 现代c++设计模式)
  • 网页制作10-html,css,javascript初认识の适用XHTML
  • 【Elasticsearch】(Java 版)
  • springai系列(二)从0开始搭建和接入azure-openai实现智能问答
  • 基于LangChain的智能体开发实战
  • MySQL之解决表中存储类型为[1,2,3]这样的字符串中去除括号[]和逗号‘,‘的问题(FIND_IN_SET+replace)
  • Python--模块(下)
  • 【北京迅为】itop-3568 开发板openharmony鸿蒙烧写及测试-第1章 体验OpenHarmony—烧写镜像
  • Rust 图形界面开发——使用 GTK 创建跨平台 GUI
  • Python 的历史进程
  • 上海电视节发布海报、宣传片:三十而励,光影新程
  • 技术派|台军首次试射“海马斯”火箭炮,如何压制这种武器?
  • 上海迪士尼蜘蛛侠主题园区正式动工,毗邻“疯狂动物城”
  • “大国重器”、新型反隐身雷达……世界雷达展全面展示尖端装备
  • 缅甸发生5.0级地震
  • 一旅客因上错车阻挡车门关闭 ,株洲西高铁站发布通报