【分治算法 3】快速选择算法(medium)(每日一题)

 🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇

                                      ⭐分治⭐

🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇🎇


前言

分治算法(Divide and Conquer),顾名思义,将一个大问题分成多个小问题,然后分别解决这些小问题,最后将它们的解合并起来得到整体的解。这个算法的核心思想是将问题分割成更小的、相同结构的子问题,然后将子问题的解合并成原问题的解。

分治算法的运行流程通常包括三个步骤:分解、解决和合并。

  1. 分解:将原问题分解成若干个规模较小的子问题。这个步骤通常通过递归实现,直到子问题足够简单可以直接求解。

  2. 解决:递归地求解子问题。这可以通过相同的方法再次应用分治算法,继续将子问题分解成更小的子问题,直到达到基本情况可以直接求解。

  3. 合并:将子问题的解合并成原问题的解。当所有子问题都解决之后,将它们的解合并起来,得到原问题的解。

分治算法通常适用于满足两个条件的问题:

  1. 可以将原问题分解成相同结构的子问题。
  2. 子问题的解可以通过合并得到原问题的解。

分治算法在计算机科学中应用广泛,例如在排序算法中具有重要地位。著名的排序算法,如归并排序和快速排序,都是基于分治算法的思想。

归并排序通过分治的方式将一个无序数组分割成更小的子数组,然后递归地对子数组进行排序,最后将排好序的子数组合并成一个有序的数组。

快速排序也是通过分治的方式将一个无序数组分割成两个子数组,然后递归地对子数组进行排序,最后合并得到完整的有序数组。

总而言之,分治算法是一种非常有用的算法设计技巧,能够有效地解决一些复杂问题。它将问题分解成较小的子问题,通过递归解决子问题,并最终将它们的解合并成整体解,从而实现高效的问题求解。 


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);
        }
    } 
}

总结

以上是总结的第三道分治的题,后续会更新一系列的分治算法相关的题哦。

点个赞👍,会让作者开心很久的,感谢阅览。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值