首页 最新 热门 推荐

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

分治算法——优选算法

  • 25-02-14 15:41
  • 2846
  • 10192
blog.csdn.net

        本章我们要学习的是分治算法,顾名思义就是分而治之,把大问题分为多个相同的子问题进行处理,其中我们熟知的快速排序和归并排序用的就是分治算法,所以我们需要重新回顾一下这两个排序。

一、快速排序(三路划分)

1.算法思想:

        首先从数列中确定一个需要排序的数(记为key),把所有key排到它的正确位置(即排序后它的位置),然后同样的方法,使用递归(分治思想)把小于key的区间与大于key的区间进行排序,直到这个区间不存在或只有一个元素时返回。

        具体方法:从左到右遍历数组,并且我们使用三个变量(left,mid,right)把数组划分为四个区间,分别表示小于key,等于key,未遍历,大于key。而mid位置就是此时遍历到的数,判断这个数与key的关系,然后把它放在对应的区间。再用同样方法将大于key和小于key的区间排序。

        注意:在此快速排序我使用了三路划分的优化方法,和对key取用随机值,这样比普通的快速排序效率要高得多,而且是一种很实用的分治算法。

2.代码实现:

  1. vector<int> sortArray(vector<int>& nums)
  2. {
  3. srand((unsigned int)time(NULL));
  4. dfs(0,nums.size()-1,nums);
  5. return nums;
  6. }
  7. void dfs(int n,int m,vector<int>& nums)
  8. {
  9. if(n>=m) return;
  10. int key=nums[n+rand()%(m-n+1)];
  11. int left=n-1,right=m+1,mid=n;
  12. while(mid
  13. {
  14. if(nums[mid]swap(nums[++left],nums[mid++]);
  15. else if(nums[mid]==key) mid++;
  16. else swap(nums[mid],nums[--right]);
  17. }
  18. dfs(n,left,nums);
  19. dfs(right,m,nums);
  20. }

二、归并排序

1.算法思想:

        对于一个乱序的数组,我们可以把一分为二,先让两个小数组有序然后再将它们合并。那么如何让这两个小数组有序呢,同样的可以把它们分别再拆开,变成四个小组,然后继续一直往下拆,直到拆到只有一个元素,那么它必然是有序的,最后进行一一合并,这整个的思路有点像二叉树的后续遍历。

2.代码实现:

  1. vector<int> tmp;
  2. vector<int> sortArray(vector<int>& nums)
  3. {
  4. tmp.reserve(nums.size());
  5. dfs(0,nums.size()-1,nums);
  6. return nums;
  7. }
  8. void dfs(int left,int right,vector<int>& nums)
  9. {
  10. if(left>=right) return;
  11. int mid=(left+right)>>1;
  12. dfs(left,mid,nums);
  13. dfs(mid+1,right,nums);
  14. int p1=left,p2=mid+1;
  15. int i=left;
  16. while(p1<=mid&&p2<=right)
  17. tmp[i++]=nums[p1]<=nums[p2]?nums[p1++]:nums[p2++];
  18. while(p1<=mid) tmp[i++]=nums[p1++];
  19. while(p2<=right) tmp[i++]=nums[p2++];
  20. for(int j=left;j<=right;j++) nums[j]=tmp[j];
  21. }

对于快速排序和归并排序,需要了解更多细节请参考下文:

【排序算法】—— 快速排序_快速排序方法-CSDN博客

【排序算法】—— 归并排序-CSDN博客

三、快速选择算法

        当我们看到这个题目的时候,可能脑子里很快想到用堆解决TopK问题,或者是使用排序来解决。 但这是一个面试题,以上两种解决方法都不足以让我们拿到offer。需要注意题目描述是任意顺序返回这k个数,而不是有序返回,那么我们就应该意识到应该还有更优的解决方法。

        对于使用堆和排序,时间复杂度都为O(nlogn),而这个题我们可以用快速选择算法,时间复杂度为O(n),这是由快速排序延伸出的一个算法。同样使用分治思想。

算法思想:

  1. class Solution {
  2. public:
  3. vector<int> smallestK(vector<int>& arr, int k)
  4. {
  5. srand((unsigned int)time(NULL));
  6. dfs(0,arr.size()-1,arr,k);
  7. return {arr.begin(),arr.begin()+k};
  8. }
  9. void dfs(int l,int r,vector<int>& arr,int k)
  10. {
  11. if(l>r) return;
  12. int key=arr[rand()%(r-l+1)+l];
  13. int left=l-1,right=r+1,mid=l;
  14. while(mid
  15. {
  16. if(arr[mid]swap(arr[++left],arr[mid++]);
  17. else if(arr[mid]==key) mid++;
  18. else swap(arr[mid],arr[--right]);
  19. }
  20. int a=left-l+1,b=mid-left-1;
  21. if(kdfs(l,left,arr,k);
  22. else if(k<=a+b) return;
  23. else dfs(right,r,arr,k-a-b);
  24. }
  25. };

四、逆序对问题

        关于这个题,最容易想到的就是暴力方法,双重循环,时间复杂度为O(n^2),毫无疑问是通过不了这个题的,这个题我们可以利用归并排序来完成计数,时间复杂度为O(nlogn)。

算法思想:

  1. class Solution {
  2. public:
  3. int count=0;
  4. vector<int> tmp;
  5. int reversePairs(vector<int>& record)
  6. {
  7. tmp.reserve(record.size());
  8. dfs(0,record.size()-1,record);
  9. return count;
  10. }
  11. void dfs(int left,int right,vector<int>& nums)
  12. {
  13. if(left>=right) return;
  14. int mid=(left+right)>>1;
  15. dfs(left,mid,nums);
  16. dfs(mid+1,right,nums);
  17. int p1=left,p2=mid+1;
  18. int i=left;
  19. while(p1<=mid&&p2<=right)
  20. {
  21. if(nums[p1]<=nums[p2]) tmp[i++]=nums[p1++];
  22. else count+=mid-p1+1, tmp[i++]=nums[p2++];
  23. }
  24. while(p1<=mid) tmp[i++]=nums[p1++];
  25. while(p2<=right) tmp[i++]=nums[p2++];
  26. for(int i=left;i<=right;i++)
  27. nums[i]=tmp[i];
  28. }
  29. };

非常感谢您能耐心读完这篇文章。倘若您从中有所收获,还望多多支持呀!74c0781738354c71be3d62e05688fecc.png

注:本文转载自blog.csdn.net的敲上瘾的文章"https://blog.csdn.net/2302_80105876/article/details/144412019"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

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

分类栏目

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

热门文章

113
数据结构与算法
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top