首页 最新 热门 推荐

  • 首页
  • 最新
  • 热门
  • 推荐

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

  • 25-03-04 20:42
  • 3505
  • 13673
blog.csdn.net

目录

  • 一、分治简介
  • 二、75.颜⾊分类
  • 三、912.排序数组
  • 四、215.数组中的第K个最⼤元素
    • 4.1 快排思想
    • 4.2 堆排序思想
    • 4.3 排序
  • 五、LCR159.库存管理 |||
    • 5.1 快排思想
    • 5.2 堆排序思想
    • 5.3 排序

一、分治简介

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

二、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 不走。

解题代码:

//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

三、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 ] 为小于基准值的时候,就需要将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 - 1]和[right + 1 , r]区间即可。

解题代码:

//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

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

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

题目解析:

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

4.1 快排思想

解题思路:

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

解题代码:

//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34

4.2 堆排序思想

解题思路:

  • 直接使用一个堆,将数组放进堆中,
  • 由于库函数创建的是小根堆,所以我们返回第nums.length - k + 1小的数即可。
//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

4.3 排序

解题思路:

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

五、LCR159.库存管理 |||

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

题目解析:

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

5.1 快排思想

解题思路:

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

解题代码:

//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

5.2 堆排序思想

解题思路:

  • 直接使用一个堆,将数组放进堆中,
  • 由于库函数创建的是小根堆,所以我们返回前cnt个数数即可。
    解题代码:
//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

5.3 排序

解题思路:

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

解题代码:

//时间复杂度: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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
注:本文转载自blog.csdn.net的鸽鸽程序猿的文章"https://blog.csdn.net/yj20040627/article/details/143685986"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接
复制链接
相关推荐
发表评论
登录后才能发表评论和回复 注册

/ 登录

评论记录:

未查询到任何数据!
回复评论:

分类栏目

后端 (14832) 前端 (14280) 移动开发 (3760) 编程语言 (3851) Java (3904) Python (3298) 人工智能 (10119) AIGC (2810) 大数据 (3499) 数据库 (3945) 数据结构与算法 (3757) 音视频 (2669) 云原生 (3145) 云平台 (2965) 前沿技术 (2993) 开源 (2160) 小程序 (2860) 运维 (2533) 服务器 (2698) 操作系统 (2325) 硬件开发 (2491) 嵌入式 (2955) 微软技术 (2769) 软件工程 (2056) 测试 (2865) 网络空间安全 (2948) 网络与通信 (2797) 用户体验设计 (2592) 学习和成长 (2593) 搜索 (2744) 开发工具 (7108) 游戏 (2829) HarmonyOS (2935) 区块链 (2782) 数学 (3112) 3C硬件 (2759) 资讯 (2909) Android (4709) iOS (1850) 代码人生 (3043) 阅读 (2841)

热门文章

113
数据结构与算法
关于我们 隐私政策 免责声明 联系我们
Copyright © 2020-2025 蚁人论坛 (iYenn.com) All Rights Reserved.
Scroll to Top