🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
⭐分治⭐
🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇
前言
分治算法(Divide and Conquer),顾名思义,将一个大问题分成多个小问题,然后分别解决这些小问题,最后将它们的解合并起来得到整体的解。这个算法的核心思想是将问题分割成更小的、相同结构的子问题,然后将子问题的解合并成原问题的解。
分治算法的运行流程通常包括三个步骤:分解、解决和合并。
分解:将原问题分解成若干个规模较小的子问题。这个步骤通常通过递归实现,直到子问题足够简单可以直接求解。
解决:递归地求解子问题。这可以通过相同的方法再次应用分治算法,继续将子问题分解成更小的子问题,直到达到基本情况可以直接求解。
合并:将子问题的解合并成原问题的解。当所有子问题都解决之后,将它们的解合并起来,得到原问题的解。
分治算法通常适用于满足两个条件的问题:
- 可以将原问题分解成相同结构的子问题。
- 子问题的解可以通过合并得到原问题的解。
分治算法在计算机科学中应用广泛,例如在排序算法中具有重要地位。著名的排序算法,如归并排序和快速排序,都是基于分治算法的思想。
归并排序通过分治的方式将一个无序数组分割成更小的子数组,然后递归地对子数组进行排序,最后将排好序的子数组合并成一个有序的数组。
快速排序也是通过分治的方式将一个无序数组分割成两个子数组,然后递归地对子数组进行排序,最后合并得到完整的有序数组。
总而言之,分治算法是一种非常有用的算法设计技巧,能够有效地解决一些复杂问题。它将问题分解成较小的子问题,通过递归解决子问题,并最终将它们的解合并成整体解,从而实现高效的问题求解。
2. 快速选择算法
题目链接:215. 数组中的第K个最大元素 - 力扣(LeetCode)
算法思路:(快速选择算法)
这道题有多种解法,比较经典的方式是用建小根堆去找这个数O(n*logk)
这里使用分治的思想解决这道问题能达到 O(n) 《算法导论》
在快排中,当我们把数组「分成三块」之后: [l, left] [left + 1, right - 1] [right, r] ,我们可以通过计算每⼀个区间内元素的「个数」,进⽽推断出我们要找的元素是 在「哪⼀个区间」⾥⾯。 那么我们可以直接去「相应的区间」去寻找最终结果就好了。
代码实现:
class Solution {
//这里用快速选择的思想去找
//先把数组分成三块,然后根据三块个数的情况看k在哪一块就去那一块找;
public int findKthLargest(int[] nums, int k) {
return find(nums,0,nums.length-1,k);
}
public void swap(int[]nums,int i,int j){
int tmp = nums[i];
nums[i] = nums[j];
nums[j] = tmp;
}
public int find(int[] nums,int l,int r,int k){
if(l>=r) return nums[l];
//选择基准元素
int key = nums[new Random().nextInt(r-l+1)+l];
int left = l-1,right = r+1,i=l;
//数组分三块
while(i<right){
if(nums[i]<key){
swap(nums,++left,i++);
}else if(nums[i] == key){
i++;
}else{
swap(nums,--right,i);
}
}
//此时数组分成 <k =k >k 三块,根据个数找k在哪一块
// [l,left] [left+1,right-1] [right,r]
int a = left-l+1,b = right-left-1,c = r-right+1;
// 根据个数找 k 的位置
if(c >= k){
return find(nums,right,r,k);
}else if(c+b >=k){
return key;
}else{
return find(nums,l,left,k-c-b);
}
}
}
总结
以上是总结的第三道分治的题,后续会更新一系列的分治算法相关的题哦。
点个赞👍,会让作者开心很久的,感谢阅览。