排序算法的简单进阶(快速排序算法,获取中位数的双指针写法)

剑指 Offer 61. 扑克牌中的顺子

Picture1.png

图片源自:力扣 

该题的关键在于找到扑克牌连子的规律,如果五张牌连着,在不考虑癞子牌的情况下无论如何都应是最大牌减最小牌为4。

如果再去掉癞子并且不考虑重复牌的情况下,应该是小于5(比如00125,00235无论怎样都会是小于五,因为没有重复牌的情况下,最多会有两个癞子,如果满足链子的情况下,只要其最大减最小会小于五,加上癞子总会满足情况)

使用集合来确认有重复牌直接return false;

设牌最小为14,牌最小为0,方便确定最大牌点数与最小牌点数。

code:

/**
 * @param {number[]} nums
 * @return {boolean}
 */
var isStraight = function(nums) {
    var set = new Set();
    var minnum = 14,maxnum = 0;
    for(var i of nums){
        if(i==0)continue;
        if(set.has(i)) return false;
        maxnum = Math.max(maxnum,i);
        minnum = Math.min(minnum,i);
        set.add(i);
    }
    return maxnum - minnum < 5
};

剑指 Offer 40. 最小的k个数

该题需要将时间复杂度降为n^2以下,容易想到使用快速排序,其时间复杂度为nlogn,可以ac

思想:

定义数组开头的数为“哨兵”,之后从数组的最右边开始向左寻找小于哨兵的值(无论如何应该从哨兵的另一边开始进行寻找。。从左开始左边会停留在一个大于哨兵值的数,但是右边开始走可能也刚好到该数停下,导致该数去了开头违反排序。),如果小于将该值赋值给左指针,再从左向右寻找大于哨兵的值,如果大于则将其赋值给右指针,左右指针相等时将开始时的哨兵值赋值给它。

code:

/**
 * @param {number[]} arr
 * @param {number} k
 * @return {number[]}
 */
var getLeastNumbers = function(arr, k) {
    var partition = function(arr,start,end){
        if(start>=end){
            return;
        }
        var i = start;
        var j = end;
        var temp_0 = arr[i];
        
        while (i<j){
            while(temp_0<arr[j] && j>i) j--;
            arr[i] = arr[j];
            while(temp_0>=arr[i] && j > i) i++;
            arr[j] = arr[i];
        }
        arr[j] = temp_0;
        partition(arr,start,j-1);
        partition(arr,j+1,end);
    }

    partition(arr, 0, arr.length-1);
    return arr.splice(0,k)
};

优化:该题仅要求输出前k个,因此在排序时可以返回排序最后的index,对比index与k的大小

如果k大于index,则只需要对后半部分进行排序,将start值更改为index+1,

如果k小于index,则需要对前半部分进行排序,将end改为index-1

由于快速排序的特点,基准点为k时即为最后结果

code:

/**
 * @param {number[]} arr
 * @param {number} k
 * @return {number[]}
 */
var getLeastNumbers = function(arr, k) {
    var partition = function(arr,start,end){
        // if(start>=end){
        //     return;
        // }
        var i = start ;
        var j = end;
        var temp_0 = arr[i];
        while (i<j){
            while(temp_0<arr[j] && j>i) j--;
            arr[i] = arr[j];
            while(temp_0>=arr[i] && j > i) i++;
            arr[j] = arr[i];
        }
        arr[j] = temp_0;
        return j
    }
    var right = arr.length-1;
    var left = 0
    var index = partition(arr, left, right);
    while (k!=index && k!=(index+1)){
        console.log(index);
        if (k> index){
            left = index+1;
            index = partition(arr,left, right);
        }
        else if(k< index){ 
            right = index-1;
            index = partition(arr,left,right);
        }
    }
    return arr.splice(0,k);
};

 

剑指 Offer 45. 把数组排成最小的数

同样是对排序的应用,但是该题需要将排序的判断条件修改为符合题意的两个数字结合最小的情况。

''+temp_0+arr[j]<=''+arr[j]+temp_0  此情况为temp0小于一个arr[j]的值,例如:13<31,所以temp0“小于”arr[j],将此条件修改到快速排序即可。

code:

/**
 * @param {number[]} nums
 * @return {string}
 */
var minNumber = function(nums) {
    var partition = function(arr,start,end){
        if(start>=end){
            return;
        }
        var i = start;
        var j = end;
        var temp_0 = arr[i];
        
        while (i<j){
            while(''+temp_0+arr[j]<=''+arr[j]+temp_0 && j>i) j--;
            arr[i] = arr[j];
            while(''+temp_0+arr[i]>=''+arr[i]+temp_0 && j > i) i++;
            arr[j] = arr[i];
        }
        arr[j] = temp_0;
        partition(arr,start,j-1);
        partition(arr,j+1,end);
    }
    partition(nums,0,nums.length-1);
    return nums.join('');
};

剑指 Offer 41. 数据流中的中位数

运用双指针来维护数组当中的中位数,初始化定义左右均为-1,当数组中有数添加进去后,令左右都加1得到0,此时中位数就是数组中唯一的值,之后再有任何数添加进去,先判断左右是否相等,不等则左加一,相等右加一(与奇偶原理相同)。

code:

/**
 * initialize your data structure here.
 */
var MedianFinder = function() {
    this.temp = [];
    this.l = -1,this.r = -1;
};

/** 
 * @param {number} num
 * @return {void}
 */
MedianFinder.prototype.addNum = function(num) {
    if (this.l == -1){
        this.l+=1;
        this.r+=1;
    }
    else{
        if(this.l == this.r){
            this.r += 1;
        }
        else this.l += 1;
    }
    this.temp.push(num);
};

/**
 * @return {number}
 */
MedianFinder.prototype.findMedian = function() {
    this.temp.sort(function(a,b){return a-b});
    if (!this.temp) return null;
    return (this.temp[this.l]+this.temp[this.r])/2
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * var obj = new MedianFinder()
 * obj.addNum(num)
 * var param_2 = obj.findMedian()
 */

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值