牛客网刷题之数组(二分法、BFPRT算法)

前言

最近大家都如火如荼的找工作,我也正在尝试,21年的招聘会看起来不是那么的友好,自己学的Java程序不知道会不会找到心仪的工作,今天七夕在这里许个愿,求个好一些公司的面试机会和offer。
学算法,学系统设计, 学更多的技术,提升自身的核心竞争力,个人的博客: https://itxingzai.xyz/,一起学习,一起进步。

题目一 二分法

题目传送门

题目1描述

实现一个有重复数字的数组查找,找到数组中第一个大于等于目标元素的元素位置,如果不存在,返回数组长度+1

输入:5,4,[1,2,4,4,5]
输出:返回值为 3
表示第一个等于4的元素

题目1分析

二分法较为简单,只是在数组中有重复的元素,并且要返回第一个元素的下标需要比直接找目标元素多几次递归。
画图解释比较简单:
计算数组中间位置
当元素向右移动时left = mid +1
向右寻找目标位置
向左边进行移动时:
如果数组中没有重复的元素:只是寻找目标值,因此对于大于的信息并没有帮助,right向左移动到mid-1的位置
左边递归寻找目标值
数组中有重复的元素,并且求大于等于目标值,需要记录当前元素的信息
向左移动寻找目标

代码如下
public class Solution {
    public int upper_bound_ (int n, int v, int[] a) {
        if(n==0)return 0;
        int left = 0;
        int right = n-1;
        int mid = 0;
        while(left<=right){
            if(left==right&&a[mid]>=v)break;
            mid = (left + right)/2;
           if(a[mid]>=v){
                right = mid;
            }else {
                left = mid+1;
            }
        }
        if(mid==n-1&&a[mid]!=v) return n+1;
        else return mid+1;
    }
}
题目二 BFPRT算法

题目传送门

题目2描述

给定一个整形数组找到数组中第K大的元素

例如
输入:[1,3,5,2,2] 5 3
输出:2 解释(5 3 2)

题目2分析

题目中的数组可能有重复的元素,之前学习算法的时候,有一个求数组中第K小的元素,也能够求数组中第k大的元素,自己将算法忘记了,看见网上讲解的程序中将求第K小的元素也当做求第K大元素进行记录。

代码如下

求数组中第K大元素

import java.util.*;

public class Finder {
    public int findKth(int[] a, int n, int K) {
        // write code here
        int bfprt = bfprt(a, 0, n-1, K);
        return a[bfprt];
    }
    public  int bfprt(int[] a,int left,int right,int k){
        //1.寻找中位数
        int mid = getmid(a,left,right);
        //2.寻找中位数的下标
        int index = getmidIndex(a, left, right, mid);
        //3.划分,得到中位数新的下标
        int newindex = partion(a,left,right,index);
        //计算右边的元素的个数,如果刚好满足K,说明当前的位置为第K大的元素
        int rank = right-newindex+1;
        if(rank==k){
            return newindex;
        }else if(rank<k){ //说明当前的范围小,因此向左边移动,寻找更多的元素
            return bfprt(a,left,newindex-1,k-rank);
        }else{//当前的元素太多,因此缩小范围,向右移动
            return bfprt(a,newindex+1,right,k);
        }
    }
    //整理数组的位置,将中位数放在一个位置,放在数组的最前面,便于计算
    public  int partion(int[] a,int left,int right,int index){
        if(left<=right){
            swap(a,index,left);
            int tmp = a[left];
            int i = left;
            int j = right;
            //将中位数的元素放中间位置,小于中位数的元素放在左边位置,将大于中位数的元素放在右边位置
            while(i != j){
                while(j>i&&a[j]>=tmp){
                    --j;
                }
                a[i] = a[j];
                while(i<j&&a[i]<=tmp){
                    ++i;
                }
                a[j]=a[i];
            }
            a[i] = tmp;
            return i;
        }
        return -1;
    }
    //以5为界,获取中位数以及中位数的中位数
    public  int getmid(int[] a, int left, int right) {
        // write code here
        if(right==left)return a[left];
        int i,k=0;
        //将数组划分为5个元素为一组的数组,分别求数组的中位数
        for(i=left;i+4<=right;i+=5){
            insertsort(a,i,i+4);
            k=i-left;
            swap(a,left+k/5,i+2);
        }
        //最后一组不足5个元素
        int n = right-i+1;
        if(n>0){
            insertsort(a,i,right);
            k=i-left;
            swap(a,left+k/5,i+n/2);
        }
        k /= 5;
        if(k==0){
            return  a[left];
        }
        return getmid(a,left,left+k);
    }
    //获取中位数元素的下标
    public  int getmidIndex(int[] a, int left, int right,int mid) {
        // write code here
        for(int i=left;i<=right;++i){
            if(a[i] == mid)return i;
        }
        return -1;
    }
     //给数组进行插入排序
    public  void  insertsort(int[] a, int left, int right){
        for(int i=left+1;i<=right;i++){
            for(int j=i;j!=left;j--){
                if(a[j-1]>a[j]){
                    swap(a,j,j-1);
                }else break;
            }
        }
    }
    //交换位置
    private  void swap(int[] a, int j, int i) {
        int temp = a[i];
        a[i] = a[j];
        a[j] = temp;
    }
}

求数组中第K小的元素

public  int bfprt(int[] a,int left,int right,int k){
        //1.寻找中位数
        int mid = getmid(a,left,right);
        //2.寻找中位数的下标
        int index = getmidIndex(a, left, right, mid);
        //3.划分,得到中位数新的下标
        int newindex = partion(a,left,right,index);
        //获取中位数当前的位置,一下位置与寻找大元素更好是一个反过程计算
        int rank = newindex - left + 1;
        if(rank==k){
            return newindex;
        }else if(rank>k){
            return bfprt(a,left,newindex-1,k);
        }else{
            return bfprt(a,newindex+1,right,k-rank);
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值