首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

[算法]——分治&归并(一)

  • 25-02-15 06:41
  • 3489
  • 6365
blog.csdn.net

 

目录

一、前言

二、正文

1.排序数组

1.1 题目解析

1.2 算法原理

1.3 具体代码

2.交易逆序对的总数

2.1 题目解析

2.2 算法原理

2.3 具体代码

三、结语


一、前言

        本文将为大家带来算法新一趴——分治&归并的学习,希望大家能够从中有所收获,如有不足,欢迎小伙伴们在评论区指出呀!!!

二、正文

1.排序数组

1. 排序数组 - 【力扣】

1.1 题目解析

        对于本题来说,题目的要求很简单,就是要求我们能够将所给的数组以升序进行排序。该题目也是很经典的排序题,本文只采取其中一种归并排序进行讲解,至于其他的排序,可转移至博主下面几篇文章,当然其中也包括更为细致的归并排序的讲解。

归并排序和计数排序

插入排序与希尔排序

1.2 算法原理

        本题要求我们将无序的数组处理成升序的数组。那么我们想,如果想要整个数组有序,是不是可以先以数组的中间为界,让左边有序,右边也有序,再将左右两边合并起来就可以了。那么如何实现左右两边都有序,是不是也要以左右两边各自中间为界,左边部分的左右两边有序,右边部分的左右两边有序,再将各自左右两边合并……直至分到只有一个元素,就不用排序了,那么上述过程,我们将一个很大的问题,即对整个数组进行排序的过程,分为排序左右两个部分,左右两部分再各自对内部左右两部分排序,然后在合并这样子一个将大问题切分成小问题的过程,就属于分治的过程,而采用这种分治思想的排序我们也叫做归并排序。

        具体的实现过程:

        1.选取中间点mid来换分数组的左右区间

        2.把左右区间进行排序

        3.合并两个有序数组,将其放到辅助数组tmp中(避免合并过程对原数组元素进行覆盖)

        4.处理原数组,即将辅助数组的元素拷贝到原数组

1.3 具体代码

  1. class Solution {
  2. public:
  3. vector<int> sortArray(vector<int>& nums) {
  4. //归并排序
  5. vector<int> tmps=nums;
  6. Mmerge_sort(nums,0,nums.size()-1,tmps);
  7. return nums;
  8. }
  9. void Merge_sort(vector<int>& nums,int left,int right,vector<int>& tmps)
  10. {
  11. if(left==right) return;
  12. //1. 选择中间点划分区间
  13. int mid=left+(right-left)/2;
  14. //2. 把左右区间排序
  15. Imerge_sort(nums,left,mid,tmps);
  16. Imerge_sort(nums,mid+1,right,tmps);
  17. //3. 合并两个有序数组
  18. int cur1=left,cur2=mid+1,i=left;
  19. while(cur1 <= mid && cur2<=right)
  20. tmps[i++]=nums[cur1]<=nums[cur2]?nums[cur1++]:nums[cur2++];
  21. while(cur1<=mid) tmps[i++]=nums[cur1++];
  22. while(cur2<=right) tmps[i++]=nums[cur2++];
  23. // 处理原数组
  24. for(int j=left;j<=right;j++)
  25. {
  26. nums[j]=tmps[j];
  27. }
  28. }
  29. };

2.交易逆序对的总数

2.交易逆序对的总数 - 【力扣】

2.1 题目解析

        本题要求我们找出所给数组中所有的逆序对,并统计其数量来返回。那么什么是逆序对,也就是在该数组中我们任意选取两个元素,只要前者的元素比后者的元素大(顺序一定是前者大于后者),即说明两者组成了一个逆序对。

        我们以【9,7,5,4,6】为例,我们很容易发现(9,7)中,前者9大于后者的7,因此(9,7)就属于一个逆序对,同理我们还可以找到其他的逆序对(9, 5), (9, 4), (9, 6), (7, 5), (7, 4), (7, 6), (5, 4),总共加起来就是有8个逆序对。

2.2 算法原理

        这题其实与上一题的思路大体相同,当我们想要找到整个数组的逆序对,是不是可以先将这个数组分为两部分,先找到左右两部分各自的逆序对,再找左右两部分的逆序对。而找左右两部分各自的逆序对,是不是依旧是左边部分划分为左右两部分,再加上左右的,右边部分划分为左右两部分,再加上左右的……直至分到一个元素不能再继续划分为止

        因此本题也可以采用分治的思想,按照上面的思路已经可以做出这道题目了,但是我们还可以再优化一步,就是当我们在判断两个元素是否为逆序对的时候,其实就相当于在做归并排序的统计一左一右这步的判断过程,因此我们可以再统计左右两部分的逆序对时,就可以顺便将左右两部分归并排序,方便下一次的逆序对的统计,从而提高了效率。具体的代码思路可以参考上一题的归并排序

        细心的小伙伴会发现上一题我们的归并排序是采取降序的版本,但其实归并排序也可以有升序的版本,因此对于本题来说,其实是有两种方法的,一种升序,一种降序。

2.3 具体代码

  1. class Solution {
  2. public:
  3. int tmp[50001];
  4. int reversePairs(vector<int>& record) {
  5. return Mmerge_count(record,0,record.size()-1);
  6. }
  7. //降序版
  8. int Mmerge_count(vector<int>& nums,int left ,int right)
  9. {
  10. if(left>= right) return 0;
  11. int mid=left+(right-left)/2;
  12. int ret =0;
  13. //分别单独统计左右两个部分
  14. ret=Mmerge_count(nums,left,mid)+Mmerge_count(nums,mid+1,right);
  15. //统计一左一右
  16. int cur1=left,cur2=mid+1,i=0;
  17. while(cur1 <= mid &&cur2 <=right)
  18. {
  19. if(nums[cur1] <= nums[cur2] )
  20. {
  21. tmp[i++]=nums[cur2++];
  22. }
  23. else {
  24. ret+=right-cur2+1;
  25. tmp[i++]=nums[cur1++];
  26. }
  27. }
  28. while(cur1<=mid) tmp[i++]=nums[cur1++];
  29. while(cur2<=right) tmp[i++]=nums[cur2++];
  30. for(int j=left;j<=right;j++)
  31. nums[j]=tmp[j-left];
  32. return ret;
  33. }
  34. //升序版
  35. int Mmerge_count(vector<int>& nums,int left ,int right)
  36. {
  37. if(left>= right) return 0;
  38. int mid=left+(right-left)/2;
  39. int ret =0;
  40. //分别单独统计左右两个部分
  41. ret=Mmerge_count(nums,left,mid)+Mmerge_count(nums,mid+1,right);
  42. //统计一左一右
  43. int cur1=left,cur2=mid+1,i=0;
  44. while(cur1 <= mid &&cur2 <=right)
  45. {
  46. if(nums[cur1] <= nums[cur2] )
  47. {
  48. tmp[i++]=nums[cur1++];
  49. }
  50. else {
  51. ret+=mid-cur1+1;
  52. tmp[i++]=nums[cur2++];
  53. }
  54. }
  55. while(cur1<=mid) tmp[i++]=nums[cur1++];
  56. while(cur2<=right) tmp[i++]=nums[cur2++];
  57. for(int j=left;j<=right;j++)
  58. nums[j]=tmp[j-left];
  59. return ret;
  60. }
  61. };

三、结语

       

        到此为止,本文有关分治中归并的部分内容到此结束了,如有不足之处,欢迎小伙伴们指出呀!

         关注我 _麦麦_分享更多干货:_麦麦_-CSDN博客

         大家的「关注❤️ + 点赞? + 收藏⭐」就是我创作的最大动力!谢谢大家的支持,我们下期见!

        欢迎大家参观我的算法专栏:

麦麦的算法专栏https://blog.csdn.net/m0_73953114/category_12866812.html

一枚积极学习,乐于分享的苏苏子
QQ名片
注:本文转载自blog.csdn.net的_麦麦_的文章"https://blog.csdn.net/m0_73953114/article/details/145446279"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

101
推荐
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top