前言
最近大家都如火如荼的找工作,我也正在尝试,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);
}
}