快速排序系列笔记 quick select

基础1: partition

Partition Array

Given an array nums of integers and an int k, partition the array (i.e move the elements in "nums") such that:

  • All elements < k are moved to the left
  • All elements >= k are moved to the right

Return the partitioning index, i.e the first index inums[i] >= k.

Example

If nums = [3,2,2,1] and k=2, a valid answer is 1.

如果控制条件是 i < j 的话, 那么在如下情况下会出错

[7,7,9,8,6,6,8,7,9,8,6,6], 10

 因为所有数字都小于10,那么i index 应该一直递增到超过j

所以应该为 i <= j

我的代码:

public class Solution {
    /**
     *@param nums: The integer array you should partition
     *@param k: As description
     *return: The index after partition
     */
    public int partitionArray(int[] nums, int k) {
        //write your code here
        int i = 0, j = nums.length - 1;
        while (i <= j) {
            if (nums[i] < k && nums[j] < k) {
                i++;
            } else if (nums[i] < k && nums[j] >= k) {
                i++;
                j--;
            } else if (nums[i] >= k && nums[j] >= k) {
                j--;
            } else if (nums[i] >= k && nums[j] < k) {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
                i++;
                j--;
            }
        }
        return i;
    }
}

其实当左边index的值比k小的时候 i可以一直递增

右边index的值比k大的时候 j可以一直递减

那么当两遍都违背的时候,做一次sawp

简洁到飞起来= =

public class Solution {
    /**
     *@param nums: The integer array you should partition
     *@param k: As description
     *return: The index after partition
     */
    public int partitionArray(int[] nums, int k) {
        if(nums == null || nums.length == 0){
            return 0;
        }

        int left = 0, right = nums.length - 1;
        while (left <= right) {

            while (left <= right && nums[left] < k) {
                left++;
            }

            while (left <= right && nums[right] >= k) {
                right--;
            }

            if (left <= right) {
                int temp = nums[left];
                nums[left] = nums[right];
                nums[right] = temp;

                left++;
                right--;
            }
        }
        return left;
    }
}

partitionArray

----------------------------------------分割线-------------------------------

Kth Largest Element in an Array

Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.

For example,
Given [3,2,1,5,6,4] and k = 2, return 5.

这种算法的均摊复杂度是o(n)

T(n) = T(n/2) + o(n)

    = T(n/4) + 0(n/2)+o(n)

   =...

平均的时间复杂度是o(nlogn), 不理想的情况就是每次partition只排除掉1个点,那么时间复杂度会退化到o(n^2)

注意几个细节:

1. helper函数是int,递归返回最后的结果,一直返回到最外面一层

2. 这里的partition和前面partition array不同, 以left节点做为pivot,然后从右边开始走,把第一个不符合的放在左边,然后左边开始走,把不符合的放在右边。最后把pivot放回去新的left节点的位置

3. 找第k个大的点 转化为找第length - k + 1的小的点

 public class Solution {
     public int findKthLargest(int[] nums, int k) {
         if (nums == null || nums.length == 0) {
             return -1;
         }
         return helper (nums, nums.length - k + 1, 0, nums.length - 1);
        //length - k + 1 convert the kth large to k‘th small one
      }
     private int helper(int[] nums, int k, int start, int end) {
         if (start == end) {
             return nums[start];
         }

         int pos = partition(nums, start, end);
         if (pos + 1 == k) {
             return nums[pos];
         } else if (pos + 1 > k) {
             return helper (nums, k, start, pos - 1);
         } else {
             /*这个地方为什么是return 下一层递归的结果,因为需要的结果在下层/下下层递归中得到,
          把这个值返回来交给最上面的一层*/
             return helper (nums, k,  pos + 1, end);
         }

     }

     public int partition(int[] nums, int l, int r) {
        // 初始化左右指针和pivot
        int left = l, right = r;
        int pivot = nums[left];

        // 进行partition
        while (left < right) {
            while (left < right && nums[right] >= pivot) {
                right--;
            }
            nums[left] = nums[right];
            while (left < right && nums[left] <= pivot) {
                left++;
            }
            nums[right] = nums[left];
        }

        // 返还pivot点到数组里面
        nums[left] = pivot;
        return left;
    }
}
    

  

时间: 2024-10-05 02:32:26

快速排序系列笔记 quick select的相关文章

Java系列笔记(1) - Java 类加载与初始化

目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一条类加载器链,一般的,我们只会用到一个原生的类加载器,它只加载Java API等可信类,通常只是在本地磁盘中加载,这些类一般就够我们使用了.如果我们需要从远

Java系列笔记(2) - Java RTTI和反射机制

目录 前言 传统的RTTI 反射 反射的实现方式 反射的性能 反射与设计模式 前言 并不是所有的Class都能在编译时明确,因此在某些情况下需要在运行时再发现和确定类型信息(比如:基于构建编程,),这就是RTTI(Runtime Type Information,运行时类型信息). 在java中,有两种RTTI的方式,一种是传统的,即假设在编译时已经知道了所有的类型:还有一种,是利用反射机制,在运行时再尝试确定类型信息. 本文主要讲反射方式实现的RTTI,建议在阅读本文之前,先了解类的加载机制(

算法系列笔记5(扩展数据结构-动态顺序统计和区间树)

在编程中,我们往往使用已有的数据结构无法解决问题,这是不必要急着创建新的数据结构,而是在已有数据结构的基础上添加新的字段.本节在上一次笔记红黑树这一基础数据结构上进行扩展,得出两个重要的应用-动态顺序统计和区间树. 动态顺序统计 在算法系列笔记2中我们在线性时间内完成了静态表的顺序统计,而这里我们在红黑树上进行扩展,在O(lgn)时间内完成该操作,主要包括返回第i 排名的元素os_select(i)和给定一个元素x,返回其排名(os_rank(x)). 思想:添加新项:在红黑树的结点上记录下该结

大连廿四2016暑假集训day1-T3(quick select&amp;linear select)

3 kth3.1 Description给定 n 个不超过 10^9 的正整数,请线性时间选择算法 (linear select)求其中的第 k 大值.3.2 Input第一行两个整数 n,k. 第二行 n 个整数,表示题目中的那 n 个正整数.3.3 Output一行,表示答案.3.4 Sample Input10 3 2 4 7 3 5 6 9 6 1 83.5 Sample Output73.6 Constraints一共 10 个测试点,每个测试点 10 分,只有当你的答案与标准答案完全

环境搭建系列笔记-目录

计划出个系列笔记,写一下如何搭建MySQL集群.RabbitMQ集群.Redis集群.Zookeeper集群.nginx.tomcat啥的. 先定个小目标,列个目录,然后搞出来这个系列. 大家有什么建议,比如想先看哪个?想让我写得多详细?想让我提供什么资源? 系列一:系统安装之centos 6.5安装与配置 系列二:准备工作之Java环境安装 系列三:数据为先之MySQL读写集群搭建 系列四:谈分布式之RabbitMQ集群搭建 系列五:谈分布式之Zookeeper集群搭建 系列六:分布缓存之Re

pluskid&#39;SVM系列笔记(可当做目录对照看)

0.训练数据对分类器性能的影响 原文链接:http://blog.pluskid.org/?p=223 1.训练数据的不平衡性对分类器性能的影响(precision .accuracy.error rate 等) 2.SVM(support vector machine)通过hyperplane切分数据,so we can have lots of reasonable hyperplane. 对于需要复杂曲线才能切分的边界:将数据映射到高维空间,这样通常都能转化成可用线性边界切分的情况, us

【转载】Java系列笔记(1) - Java 类加载与初始化

Java系列笔记(1) - Java 类加载与初始化 原文地址:http://www.cnblogs.com/zhguang/p/3154584.html 目录 类加载器 动态加载 链接 初始化 示例 类加载器 在了解Java的机制之前,需要先了解类在JVM(Java虚拟机)中是如何加载的,这对后面理解java其它机制将有重要作用. 每个类编译后产生一个Class对象,存储在.class文件中,JVM使用类加载器(Class Loader)来加载类的字节码文件(.class),类加载器实质上是一

菜鸟学设计模式系列笔记之Prototype模式(原型模式)

菜鸟学设计模式系列笔记之Prototype模式: Intent: 用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象 Motivation:以一个已有的对象作为原型,通过它来创建新的对象. 在增加新的对象的时候,新对象的细节创建工作由自己来负责,从而使新对象的创建过程与框架隔离开来. 应用场景: (1)当一个系统应该独立于它的产品创建.构成和表示时 (2)当要实例化的类是在运行时刻指定时,例如动态加载 (3)为了避免创建一个产品类层次平行的工厂类层次时 (4)当一个类的实例只能有几个

飘逸的python - 大数据TopK问题的quick select解法

TopK问题,即寻找最大的K个数,这个问题非常常见,比如从1千万搜索记录中找出最热门的10个关键词. 方法一: 先排序,然后截取前k个数. 时间复杂度:O(n*logn)+O(k)=O(n*logn). 方法二: 最小堆. 维护容量为k的最小堆.根据最小堆性质,堆顶一定是最小的,如果小于堆顶,则直接pass,如果大于堆顶,则替换掉堆顶,并heapify整理堆,其中heapify的时间复杂度是logk. 时间复杂度:O(k+(n-k)*logk)=O(n*logk) 方法三: 本文的主角.quic