【算法】——快排,分治算法合集

简介: 本文主要介绍排序中的快排思想的应用,做到一法通万法的效果


image.gif 编辑

阿华代码,不是逆风,就是我疯

你们的点赞收藏是我前进最大的动力!!

希望本文内容能够帮助到你!!

目录

一:颜色分类

二:排序数组(分三组快排)

三:数组中的第k个最大元素

四:前k的最小的元素

方法一:冒泡排序

方法二:基础快排思想

方法三:优化版本


本文主要介绍了排序中的快排算法,和优化思路,按照题号做,难度层层递进,第二题是最基础的模版,第三题、第四题在此基础上进行算法优化

一:颜色分类

75. 颜色分类

image.gif 编辑

image.gif 编辑

class Solution {
    
    public void sortColors(int[] nums) {
        int left = -1 , right = nums.length ; 
        //先把框架搭出来
        // 遍历数组
        for(int i = 0 ; i < right ; ){
            if(nums[i] == 0){
                left++;
                swap(nums,i,left);
                i++;
            }else if(nums[i] == 1){
                i++;
            }else{
                right--;
                swap(nums,i,right);
            }
        }
    }
    //交换数组中的两个元素传入数组和下标
    public void swap(int[] nums,int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
}

image.gif

二:排序数组(分三组快排)

912. 排序数组

image.gif 编辑

image.gif 编辑

class Solution {
    public int[] sortArray(int[] nums) {
        int n = nums.length;
        for(int j = n-1 ; j > 0 ; j--){
            for(int i = 0 ; i < j ;){
                if(nums[i] > nums[i+1]){
                    swap(nums , i , i+1);
                    i++;
                }else{
                    i++;
                }
            }
        }
        return nums;
    }
    public void swap(int nums[] , int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
}

image.gif

image.gif 编辑

image.gif 编辑

image.gif 编辑

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;
        }
        // Random random = new Random();
        // int index = random.nextInt(r - l + 1) + l;//随机下标
        // int key = nums[index];//随机数
        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,i++,++left);
            }else if(nums[i] == key){
                i++;
            }else{
                swap(nums,i,--right);
                //i++;不能++换过来的数还是一个没有被排序的数
            }
        }
        quickSort(nums,l,left);
        quickSort(nums,right,r);
    }
    public void swap(int[] nums , int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
}

image.gif

三:数组中的第k个最大元素

215. 数组中的第K个最大元素

第k个最大的元素,重复元素也算

易错点

①递归出口的判断(l == r)

②while循坏的条件(l < right)

③i的初始值是l(很重要,因为划分区间后,i是从l开始移动的)

④优化的三个条件,各个区间的元素个数,需要随机应变,判断条件要想好

⑤方法的返回值类型,int或者void,如果为int类型,递归出口和优化的三个条件中写返回就可以了

⑥最稳妥的方法就是不优化,先给整个数组进行完全快排,然后在排序好的数组中,进行结果的查找

image.gif 编辑

image.gif 编辑

class Solution {
    public int findKthLargest(int[] nums, int k) {
        //1:实现递归排序,传入数组,左边界,右边界,k
        int l = 0 , r = nums.length-1;
        return quickSort(nums,l,r,k);
    }
    // 把数组分成三部分
    public int quickSort(int[] nums , int l , int r , int k){
        //递归出口
        if(l == r){
            return nums[l];
        }
        //产生随机数作为下标,作为划分三部分的基准值
        Random random = new Random();
        int num = random.nextInt(r - l + 1);
        int index = num + l;
        int key = nums[index];
        int left = l-1 , right = r+1 , i = l;
        while(i < right){
            if(nums[i] > key){
                swap(nums , i , --right);
            }else if(nums[i] == key){
                i++;
            }else{
                swap(nums , i++ , ++left);//此处i++是因为 >key的值和=key的值发生了交换
            }
        }
        //根据划分的三个部分在找
        // 三个部分的区间为[l,left]  [left+1,right-1]  [right,r]
        int a = left-l+1;
        int b = right-left-1;
        int c = r-right+1;
        if(c >= k){
            return quickSort(nums,right,r,k);
        }else if(b + c >= k){
            return key;
        }else{
            return quickSort(nums,l,left,k-b-c);
        }
    }
    public void swap(int[] nums , int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
}

image.gif

四:前k的最小的元素

LCR 159. 库存管理 III

前k的最小的元素

方法一:冒泡排序

image.gif 编辑

class Solution {
    public int[] inventoryManagement(int[] stock, int cnt) {
        //方法一:冒泡排序
        int n = stock.length;
        for(int i = 0 ; i < n ; i++){
            for(int j = n-1 ; j > i ; j--){
                if(stock[j] < stock[j-1]){
                    //把小的元素往前面放
                    swap(stock , j , j-1);
                    
                }
            }    
        }
        int[] ret = new int[cnt];
        for(int i = 0 ; i < cnt ; i++){
            ret[i] = stock[i];
        }
        return ret;
    }
    public void swap(int[] stock , int a , int b){
        int tem = stock[a];
        stock[a] = stock[b];
        stock[b] = tem;
    } 
}

image.gif

方法二:基础快排思想

image.gif 编辑

class Solution {
    public int[] inventoryManagement(int[] nums, int cnt) {
        //方法二:快排分三部分思想
        int l = 0 , r = nums.length-1;
        quickSort(nums,l,r);
        int[] ret = new int[cnt];
        for(int i = 0 ; i < cnt ; i++){
            ret[i] = nums[i];
        }
        return ret;
    }
    public void quickSort(int[] nums , int l , int r){
        int left = l - 1 , right = r + 1 , i = l ; 
        if(l >= r){
            return;
        }
        // 在[l,r]区间进行排序
        // 产生随机数
        int index = new Random().nextInt( r - l + 1) + l;
        int key = nums[index];
        while(i < right){
            //小于的情况实际上就是,右边界和右边界元素的交换
            if(nums[i] < key){
                swap(nums,++left,i++);
            }else if(nums[i] == key){
                i++;
            }else{
                swap(nums,--right,i);//换过去的是未排序的元素
            }
        }
        quickSort(nums,l,left);
        quickSort(nums,right,r);
    }
    public void swap(int[] nums , int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
    
}

image.gif

方法三:优化版本

太快了2msNB

找前k个最小元素,每次递归都可以舍弃好多元素

image.gif 编辑

class Solution {
    public int[] inventoryManagement(int[] nums, int cnt) {
        //方法三:快排分三部分思想
        int l = 0 , r = nums.length-1;
        int k = cnt;
        quickSort(nums,l,r,k);
        int[] ret = Arrays.copyOf(nums,k);
        return ret;
        
    }
    public void quickSort(int[] nums , int l , int r , int k){
        int left = l - 1 , right = r + 1 , i = l ; 
        //递归这里的区间一定要想好,非常容易出错
        if(l >= r){
            return;
        }
        // 在[l,r]区间进行排序
        // 产生随机数
        int index = new Random().nextInt( r - l + 1) + l;
        int key = nums[index];
        //i小于right是基于这个key进行排序,循环的条件很重要
        while(i < right){
            //小于的情况实际上就是,右边界和右边界元素的交换
            if(nums[i] < key){
                swap(nums,++left,i++);
            }else if(nums[i] == key){
                i++;
            }else{
                swap(nums,--right,i);//换过去的是未排序的元素
            }
        }
        //根据划分的三个部分在找
        // 三个部分的区间为[l,left]  [left+1,right-1]  [right,r]
        int a = left-l+1;
        int b = right-left-1;
        int c = r-right+1;
        if(k < a){
            quickSort(nums,l,left,k);
        }else if(k <= a + b){
            return;
        }else if(k > a + b){
            quickSort(nums,right,r,k-a-b);
        }
    }
    public void swap(int[] nums , int a , int b){
        int tem = nums[a];
        nums[a] = nums[b];
        nums[b] = tem;
    }
    
}

image.gif


相关文章
|
8月前
|
人工智能 自然语言处理 算法
当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
【2月更文挑战第24天】当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
76 2
当prompt策略遇上分治算法,南加大、微软让大模型炼成“火眼金睛”
|
8月前
|
存储 缓存 算法
【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!
【数据结构与算法】【小白也能学的数据结构与算法】递归 分治 迭代 动态规划 无从下手?一文通!!!
|
6月前
|
算法 开发者 Python
惊呆了!Python算法设计与分析,分治法、贪心、动态规划...这些你都会了吗?不会?那还不快来学!
【7月更文挑战第10天】探索编程巅峰,算法至关重要。Python以其易读性成为学习算法的首选。分治法,如归并排序,将大问题拆解;贪心算法,如找零问题,每步求局部最优;动态规划,如斐波那契数列,利用子问题解。通过示例代码,理解并掌握这些算法,提升编程技能,面对挑战更加从容。动手实践,体验算法的神奇力量吧!
81 8
|
6月前
|
算法 Python
算法不再难!Python分治法、贪心、动态规划实战解析,轻松应对各种算法挑战!
【7月更文挑战第8天】掌握Python算法三剑客:分治、贪心、动态规划。分治如归并排序,将大问题拆解递归解决;贪心策略在每步选最优解,如高效找零;动态规划利用子问题解,避免重复计算,解决最长公共子序列问题。实例展示,助你轻松驾驭算法!**
86 3
|
2月前
|
算法 Python
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果
在Python编程中,分治法、贪心算法和动态规划是三种重要的算法。分治法通过将大问题分解为小问题,递归解决后合并结果;贪心算法在每一步选择局部最优解,追求全局最优;动态规划通过保存子问题的解,避免重复计算,确保全局最优。这三种算法各具特色,适用于不同类型的问题,合理选择能显著提升编程效率。
73 2
|
5月前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
6月前
|
算法 Python
Python算法高手进阶指南:分治法、贪心算法、动态规划,掌握它们,算法难题迎刃而解!
【7月更文挑战第10天】探索Python算法的精华:分治法(如归并排序)、贪心策略(如找零钱问题)和动态规划(解复杂问题)。通过示例代码揭示它们如何优化问题解决,提升编程技能。掌握这些策略,攀登技术巅峰。
158 2
|
6月前
|
算法 程序员 Python
算法小白到大神的蜕变之路:Python分治法、贪心、动态规划,一步步带你走向算法巅峰!
【7月更文挑战第9天】探索算法之旅,以Python解锁编程高手之路。分治法如二分查找,将复杂问题拆解;贪心算法解决活动选择,每次选取局部最优;动态规划求斐波那契数列,避免重复计算,实现全局最优。每一步学习,都是编程能力的升华,助你应对复杂挑战,迈向算法大师!
55 1
|
6月前
|
存储 算法 Python
Python算法界的秘密武器:分治法巧解难题,贪心算法快速决策,动态规划优化未来!
【7月更文挑战第9天】Python中的分治、贪心和动态规划是三大关键算法。分治法将大问题分解为小问题求解,如归并排序;贪心算法每步选局部最优解,不保证全局最优,如找零钱;动态规划存储子问题解求全局最优,如斐波那契数列。选择合适算法能提升编程效率。
83 1
|
6月前
|
存储 算法 Python
震撼!Python算法设计与分析,分治法、贪心、动态规划...这些经典算法如何改变你的编程世界!
【7月更文挑战第9天】在Python的算法天地,分治、贪心、动态规划三巨头揭示了解题的智慧。分治如归并排序,将大问题拆解为小部分解决;贪心算法以局部最优求全局,如Prim的最小生成树;动态规划通过存储子问题解避免重复计算,如斐波那契数列。掌握这些,将重塑你的编程思维,点亮技术之路。
88 1