这个题的思路不止是二分,还有别的方法。别的方法在这里只是提一下思路。第一种: 将学校录取分数线个学生估分放在一个数组里,进行排序,然后找到学生估分,找到离学生估分最近的学校分数线,看两个学校谁与学生估分差值最小。前提条件得对学生估分和学校分数线分别弄个标记,这样才能判断谁是学校分数线,谁是学生估分。 第二种: 使用快慢指针,一个指针a指向学校分数线,一个指针b指向学生估分,如果a指向的分数小于b指向的分数并且(a+1)指向的分数大于b指向的分数,这时候就找到区间,判断哪个小就行。如果a指向的分数小,(a+1)指向的分数也小,那么a++;当找到对应区间并且计算完成后,b++。
接下来就是二分查找的过程: 先对学校分数线进行排序,然后就遍历学生估分,找到学生估分的对应区间。
for(int i=1;i<=n;i++) {
int left=1,right=m;
while(left<(right-1)) {
//这样能保证学生成绩在两个学校之间,如果是left<right,得到的就会是left==right
int mid=(left+right)/2;
if(stu[i]>=school[mid]) {
left=mid;
}
else right=mid;
}//找到学生估值所在哪两个学校的录取分数线之间
x=Math.min(Math.abs(stu[i]-school[left]),Math.abs(school[right]-stu[i]));
ans+=x;
}
这里要说明几个和普通二分查找不同的点:
1.循环结束的条件是left<(right-1),这样能保证最后的left和right指向的不是一个元素,因为这样循环结束的条件是left==right-1,如果是正常的二分查找,这里是left <=right,这样跳出循环的条件就是left>right,一旦到了这里,就说明没有找到。
2.如果发现查找的值比中间的值大,left=mid,因为这里是要确定一个区间,如果mid 刚好是区间的左边,那么正确的区间就是mid到right,如果和普通的二分查找一样是left=mid+1,这样就会改变区间的范围。
上边的while循环跳出来以后,就是确定出来学生成绩在学校录取分数线的范围了,left表示左边界,right表示右边界,然后一样判断left和right谁跟学生估分的差值最小。
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
int m=sc.nextInt();
int n=sc.nextInt();
int[] school=new int[m+1];
int[] stu=new int[n+1];
for(int i=1;i<=m;i++)
school[i]=sc.nextInt();
for(int j=1;j<=n;j++)
stu[j]=sc.nextInt();
Arrays.sort(school,1,m+1);
int ans=0,x=0;
for(int i=1;i<=n;i++) {
int left=1,right=m;
while(left<(right-1)) {
//这样能保证学生成绩在两个学校之间,如果是left<right,得到的就会是left==right
int mid=(left+right)/2;
if(stu[i]>=school[mid]) {
left=mid;
}
else right=mid;
}//找到学生估值所在哪两个学校的录取分数线之间
x=Math.min(Math.abs(stu[i]-school[left]),Math.abs(school[right]-stu[i]));
ans+=x;
}
System.out.print(ans);
}
}