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

目录

一、分治简介

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

二、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 为0的时候,就需要将nums i 与nums left 交换,并且left 和 i 都要向后走一步,因为nums left 是1,就算left = i使得nums left 是0,逻辑也一样。
  • 当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指针 + 随机选取基准。
  • 随机选取基准:在要排序区间中等可能得随机抽取一个元素来当基准值,numsnew Random().nextInt(right - left + 1) + left;
  • 3指针,跟上面颜色分类思路一样。
  • l , r 是待排序区间, l , left - 1 里面是小于基准值的数, left , i - 1是等于基准值的数, i , right 是待排序区, right + 1 , r 是大于基准值的数。
  • 当nums i 为小于基准值的时候,就需要将nums i 与nums left 交换,并且left 和 i 都要向后走一步,因为nums left 是等于基准值,就算left = i使得nums left 是小于基准值,逻辑也一样。
  • 当nums i 为等于基准值的时候,直接 i 向后走一步即可。
  • 当nums i 为大于基准值的时候,就需要将nums i 与nums right 交换,并且right要向后走一步,而 i 不走。
  • 在排序 l , left - 1right + 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;
    }
}
相关推荐
hans汉斯5 分钟前
《软件工程与应用》期刊推荐&10月版面征稿中
图像处理·人工智能·深度学习·算法·音视频·软件工程
叠层归一研究院18 分钟前
AGI 系统(八):符号范畴嵌入函子 — SymCat ↪ C_M107 严格化
c语言·开发语言·人工智能·算法·transformer·agi
其美杰布-富贵-李1 小时前
08 进阶评估指标与算法特定指标
人工智能·算法
.道阻且长.2 小时前
5.LeetCode算法习题讲解--双指针--有效三角形的个数
算法·leetcode·职场和发展
我是海飞2 小时前
杰理JL703N SSD1306 OLED(128x64) 点阵屏移植说明
单片机·算法·嵌入式·音频·杰理
OH_TPC2 小时前
HarmonyOS APP开发---“滤镜大师“图像处理App,需要用到这个库
java·图像处理·华为·harmonyos·鸿蒙
wabs6663 小时前
关于图论【最短路径之Bellman_ford 算法(单源有限最短路)|卡码网96.城市间货物运输III的思考】
数据结构·算法·图论·卡码网·bellman_ford·单源有限最短路
imaol14 小时前
链表 -- 环链表
java·前端·链表
imaol14 小时前
链表 -- 双向链表
java·前端·链表
2601_963869954 小时前
【计算机毕业设计】基于Java的相框定制系统的设计与实现
java·开发语言·课程设计