【分治算法 4】最小的 k 个数(medium)(每日一题)

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

                                      ⭐分治⭐

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


前言

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

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

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

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

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

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

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

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

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

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

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


2. 最⼩的k个数(medium)

题目链接:LCR 159. 库存管理 III - 力扣(LeetCode)

算法思路:(快速选择算法)

在快排中,当我们把数组「分成三块」之后: [l, left] [left + 1, right - 1] [right, r] ,我们可以通过计算每⼀个区间内元素的「个数」,进⽽推断出最⼩的k个数在哪 些区间⾥⾯。 那么我们可以直接去「相应的区间」继续划分数组即可。

这道题其实有很多做法,

1. 直接排序  O(n * logN)

2.堆实现  O(n * logK)

3.分治     O(N)               这里只实现第三种做法,如果另外两种有需求的话可以在评论区评论.

 代码实现:

package Divide_and_Conquer;

import java.util.Arrays;
import java.util.Random;

public class Solution5 {
    public static void main(String[] args) {
        System.out.println(Arrays.toString(inventoryManagement(new int[]{0, 0, 1, 2, 4, 2, 2, 3, 1, 4}, 8)));
    }

    public static int[] inventoryManagement(int[] stock, int cnt) {
       int[] arr = new int[cnt]; 
       if(stock.length==0||cnt==0){
            return arr;
        }
      //这里其实有很多种做法,本题只用分治的方式来解答这道题
      //这道题和上道第k大的数很相似,那个只用找一个数,这个是找连续的几个数
      //但实际上做法是一样的 找最小的k个数
      //把数组分三块,去基准元素里找对应个数的数
      
      find(stock,0,stock.length-1,cnt);
      for(int i =0;i<cnt;i++){
        arr[i] = stock[i];
      }
      return arr;
    }
    public static void swap(int[] nums,int i ,int j ){
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
    public static void find(int[] nums,int l,int r,int k){
       //先找基准元素
       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);
           }
       }
         //看个数来找
         int c = r-right+1,b=right-left-1,a=left-l+1;
         if(a>k){
            // 在左边里面排一下再找
            find(nums,l,left,k);
         } else if(a+b>=k){  
            return;
         }else{
            find(nums,right,r,k-a-b);
         }
       
    }
}

总结

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

关于分治算法中使用快速排序变形的题目就到这里了,后继续更新 归并排序对分治算法的应用。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值