【算法】【优选算法】分治(上)

目录

一、分治简介

分治:分而治之,就是将一个大问题拆分为多个小问题,逐一解决。

二、75.颜⾊分类

题目链接:75.颜⾊分类

题目描述:

题目解析:

  • 就是给一个只含0 1 2 的数组,排序。

解题思路:

  • 我们使用3个指针将数组分为4段。
  • 0, left - 1 \]里面是0,\[ left , i - 1\]是1,\[ i , right \]是待排序区,\[ right + 1 , nums.length - 1 \]是2。

  • 当nums[ i ] 为1的时候,直接 i 向后走一步即可。
  • 当nums[ i ] 为2的时候,就需要将nums[ i ] 与nums[ right ]交换,并且right要向后走一步,而 i 不走。

解题代码:

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(1)
class Solution {
    public void sortColors(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        //数组分三块[ 0, left - 1 ],[ left , right ],[ right + 1 , nums.length - 1 ]
        for(int i = 0; i <= right; i++) {
            if(nums[i] == 0) swap(nums,left++,i);
            else if(nums[i] == 2) swap(nums,right--,i--);
        }
        
    }
    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

三、912.排序数组

题目链接:912.排序数组

题目描述:

题目解析:

  • 给数组排序。

解题思路:

  • 我们使用快排来解决,并且使用 3指针 + 随机选取基准。
  • 随机选取基准:在要排序区间中等可能得随机抽取一个元素来当基准值,nums[new Random().nextInt(right - left + 1) + left];
  • 3指针,跟上面颜色分类思路一样。
  • l , r \]是待排序区间, \[ l , left - 1 \]里面是小于基准值的数,\[ left , i - 1\]是等于基准值的数,\[ i , right \]是待排序区,\[ right + 1 , r \]是大于基准值的数。

  • 当nums[ i ] 为等于基准值的时候,直接 i 向后走一步即可。
  • 当nums[ i ] 为大于基准值的时候,就需要将nums[ i ] 与nums[ right ]交换,并且right要向后走一步,而 i 不走。
  • 在排序[ l , left - 1]和[right + 1 , r]区间即可。

解题代码:

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(1)
import java.util.*;
class Solution {
    public int[] sortArray(int[] nums) {
        quickSort(nums, 0 , nums.length - 1);
        return nums;
    }
    //快排
    public void quickSort(int[] nums, int l, int r) {
        if(l >= r) return;
        int left = l;
        int right = r;
        //随机找基准
        int key = nums[new Random().nextInt(right - left + 1) + left];
        //数组分三块[ l, left - 1 ],[ left , right ],[ right + 1 , r ]
        for(int i = left; i <= right; i++) {
            if(nums[i] < key) swap(nums,left++,i);
            else if(nums[i] > key) swap(nums,right--,i--);
        }

        quickSort(nums,l,left-1);
        quickSort(nums,right+1,r);
    }
     public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

四、215.数组中的第K个最⼤元素

题目链接:215.数组中的第K个最⼤元素

题目描述:

题目解析:

  • 返回数组中第k大的数。

4.1 快排思想

解题思路:

  • 我们使用上面的快排思想,只要在分个类讨论第k大的数在哪个区间即可。
  • 当[ right + 1 , r ]区间中包含要找的数,直接在调用即可。
  • 当[ left , right ]区间中包含要找的数,直接返回基准值。
  • 当[ l, left - 1 ]区间中包含要找的数,调用是,传参就是在该区间找区间中(第k- 前两区间长度)的数。

解题代码:

java 复制代码
//时间复杂度:O(n)
//空间复杂度:O(1)
import java.util.*;
class Solution {
    public int findKthLargest(int[] nums, int k) {
        return qsort(nums,0,nums.length-1,k);
    }
    //快排返回第k大的数。
    public int qsort(int[] nums, int l, int r, int k) {
        int left = l;
        int right = r;
        //随机找基准
        int key = nums[ new Random().nextInt(r - l + 1) + l];
        //数组分三块[ l, left - 1 ],[ left , right ],[ right + 1 , r ]
        for(int i = left; i <= right; i++) {
            if(nums[i] < key) swap(nums,left++,i);
            else if(nums[i] > key) swap(nums,right--,i--);
        }
        //每个区间的长度
        int litLength = left - l;
        int midLength = right - left + 1;
        int bigLength = r - right;

		//分类讨论
        if(bigLength >= k) return qsort(nums, right+1, r, k);
        else if(midLength + bigLength >= k) return key;
        else return qsort(nums, l, left-1, k- midLength - bigLength);
    }
     public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

4.2 堆排序思想

解题思路:

  • 直接使用一个堆,将数组放进堆中,
  • 由于库函数创建的是小根堆,所以我们返回第nums.length - k + 1小的数即可。
java 复制代码
//时间复杂度:O(NlogK)
//空间复杂度:O(n)
import java.util.*;
class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(int i = 0; i < nums.length; i++) {
            queue.add(nums[i]);
        }
        int ret = 0;
        for(int i = 0; i <  nums.length - k + 1; i++) {
            ret = queue.poll();
        }
        return ret;
    }
}

4.3 排序

解题思路:

  • 直接调用库函数将数组排序,返回即可。
java 复制代码
//时间复杂度:O(NlogN)
//空间复杂度:O(logN)
import java.util.*;
class Solution {
    public int findKthLargest(int[] nums, int k) {
        Arrays.sort(nums);
        return nums[nums.length - k];
    }
}

五、LCR159.库存管理 |||

题目链接:LCR159.库存管理 |||

题目描述:

题目解析:

  • 其实就是返回数组中前k个最小的数的集合

5.1 快排思想

解题思路:

  • 我们使用上面的快排思想,只要在分个类讨论第k大的数在哪个区间即可。
  • 当[ l, left - 1 ]区间中包含要找的数,直接在调用即可。
  • 当[ left , right ]区间中包含要找的数,直接返回。
  • 当[ right + 1 , r ]区间中包含要找的数,调用是,传参就是在该区间找区间中(第k- 前两区间长度)的数。
  • 细节处理:这里的cnt是可以等于0和数组长度的,单独考虑,等于0返回空数组,等于数组长度,返回整个数组即可。

解题代码:

java 复制代码
//时间复杂度:O(N)
//空间复杂度:O(cnt)
import java.util.*;
class Solution {
    public int[] inventoryManagement(int[] nums, int cnt) {
    	//特殊情况
        if(cnt == 0) return new int[]{};
        if(cnt == nums.length) return nums;
        
        qsort(nums, 0, nums.length-1, cnt);
        int[] ret = new int[cnt];
        for(int i = 0; i < cnt; i++) 
            ret[i] = nums[i];

        return ret; 
    }
    //快排
    public void qsort(int[] nums, int l, int r, int k) {
        int left = l;
        int right = r;
        int key = nums[new Random().nextInt(r-l+1)+l];
        //数组分三块[ l, left - 1 ],[ left , right ],[ right + 1 , r ]
        for(int i = l; i <= right; i++) {
            if(nums[i] < key) swap(nums, left++, i);
            else if(nums[i] > key) swap(nums,right--, i--);
        }
        //每个区间的长度
        int litLength = left - l;
        int midLength = right - left + 1;
        int bigLength = r - right;
		//分类讨论
        if(litLength >= k) qsort(nums, l, left-1, k);
        else if(litLength+midLength >= k) return;
        else qsort(nums,right+1, r, k-litLength-midLength);
    }
    public void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

5.2 堆排序思想

解题思路:

  • 直接使用一个堆,将数组放进堆中,
  • 由于库函数创建的是小根堆,所以我们返回前cnt个数数即可。
    解题代码:
java 复制代码
//时间复杂度:O(NlogCNK)
//空间复杂度:O(n)
import java.util.*;
class Solution {
    public int[] inventoryManagement(int[] nums, int cnt) {
        if(cnt == 0) return new int[]{};
        if(cnt == nums.length) return nums;

        PriorityQueue<Integer> queue = new PriorityQueue<>();
        for(int i = 0; i < nums.length; i++) 
            queue.add(nums[i]);
        int[] ret = new int[cnt];
        for(int i = 0; i < cnt; i++) {
            ret[i] = queue.poll();
        }
        return ret;
    }
}

5.3 排序

解题思路:

  • 直接调用库函数将数组排序,返回即可。

解题代码:

java 复制代码
//时间复杂度:O(NlogN)
//空间复杂度:O(logN+cnk)
import java.util.*;
class Solution {
    public int[] inventoryManagement(int[] nums, int cnt) {
        if(cnt == 0) return new int[]{};
        if(cnt == nums.length) return nums;

       Arrays.sort(nums);
        int[] ret = new int[cnt];
        for(int i = 0; i < cnt; i++) {
            ret[i] = nums[i];
        }
        return ret;
    }
}
相关推荐
蒙奇D索大5 分钟前
【数据结构】图解图论:度、路径、连通性,五大概念一网打尽
数据结构·考研·算法·图论·改行学it
bing_1589 分钟前
JVM 每个区域分别存储什么数据?
java·jvm
uhakadotcom9 分钟前
2025年春招:如何使用DeepSeek + 豆包优化简历,轻松敲开心仪公司的大门
算法·面试·github
zzhz92511 分钟前
Jmeter(性能指标、指标插件、测试问题、面试题、讲解稿)
java·jvm·jmeter
小白狮ww13 分钟前
Retinex 算法 + MATLAB 软件,高效率完成图像去雾处理
开发语言·人工智能·算法·matlab·自然语言处理·图像识别·去雾处理
cwtlw25 分钟前
java基础知识面试题总结
java·开发语言·学习·面试
昵称为空C27 分钟前
SpringBoot编码技巧-ScheduledExecutorService轮询
java·spring boot·后端
小杨xyyyyyyy28 分钟前
JVM - 垃圾回收器常见问题
java·jvm·面试
西元.31 分钟前
多线程循环打印
java·开发语言·jvm
ml1301852887438 分钟前
DeepSeek 助力心理医生小程序赋能!心理咨询小程序 线上咨询平台搭建
java·开发语言·小程序