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

目录

一、分治简介

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

二、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;
    }
}
相关推荐
Unstoppable224 分钟前
代码随想录算法训练营第 56 天 | 拓扑排序精讲、Dijkstra(朴素版)精讲
java·数据结构·算法·
qinyia19 分钟前
WisdomSSH解决docker run命令中log-opt参数不支持导致的容器创建失败问题
java·docker·eureka
饕餮怪程序猿29 分钟前
A*算法(C++实现)
开发语言·c++·算法
电饭叔33 分钟前
不含Luhn算法《python语言程序设计》2018版--第8章14题利用字符串输入作为一个信用卡号之二(识别卡号有效)
java·python·算法
小付爱coding1 小时前
Claude Code安装教程【windows版本】
java·git·python
**蓝桉**1 小时前
数组的执行原理,java程序的执行原理
java·开发语言
2301_800256111 小时前
8.2 空间查询基本组件 核心知识点总结
数据库·人工智能·算法
不穿格子的程序员1 小时前
从零开始写算法——矩阵类题:矩阵置零 + 螺旋矩阵
线性代数·算法·矩阵
YDS8291 小时前
MyBatis-Plus精讲 —— 从快速入门到项目实战
java·后端·spring·mybatis·mybatis-plus
BBB努力学习程序设计1 小时前
Java条件判断:程序的"决策大脑"
java