1.算法题目
金块问题:一个老板有一袋金块,里面有n块金子。每个月,老板会从袋子中拿出两个金块奖励两名表现优 秀的雇员。按规矩,最优秀的雇员将得到袋中最重的金块,排名第二的雇员将得到袋中最轻的金块。如果老板周期 性地往袋中加入新的金块,那么每个月他都要找出最重和最轻的金块。假设有一台比较质量的仪器,我们希望用尽 量少的比较次数找出最重和最轻的金块。
2.实现代码
/**
* 获取索引范围内的最大最小值
*
* @param arry 数组
* @param l 数组的左边索引
* @param r 数组的右边索引
* @return
*/
public static int[] gold(int[] arr, int l, int r) {
//用于存储最大最小值,0下标存储最小值,1下标存储最大值
int[] minmax = new int[2];
if (l == r) {
minmax[0] = arr[l];
minmax[1] = arr[l];
return minmax;
}
//递归
// 将数组分为左右两边,分别求最大最小
int[] leftarr = gold(arr, l, (l + r) / 2);
int[] rightarr = gold(arr, (l + r) / 2 + 1, r);
// 使用左边返回的最大最小值和右边的进行比较,返回最终的最大最小值
//最小值
if (leftarr[0] > rightarr[0]) {
minmax[0] = rightarr[0];
} else {
minmax[0] = leftarr[0];
}
//最大值
if (leftarr[1] < rightarr[1]) {
minmax[1] = rightarr[1];
} else {
minmax[1] = leftarr[1];
}
return minmax;
}
3.实现思路
分治法求解问题的过程是整个问题分解成若干个小问题后再分而治之。
1.先将传入的数组分成若干个数组,第一次分成左右两边,第二次分成左右左右四个数组..... leftarr,rightarr此时一直都没有被赋值,也会一直调用gold本身,直至有返回值才会向上传递,代码也就是这一段
// 将数组分为左右两边,分别求最大最小
int[] leftarr = gold(arr, l, (l + r) / 2);
int[] rightarr = gold(arr, (l + r) / 2 + 1, r);
2.当leftarr,rightarr分割成长度为1,此时l=r,并且最大最小值都为他本身,将他赋值给返回的数组minmax,此时leftarr,rightarr也就有了返回值
if (l == r) {
minmax[0] = arr[l];
minmax[1] = arr[l];
return minmax;
}
3.当leftarr,rightarr都有返回值,可以进行比较找出最大值最小值赋值给minmax,这样minmax最大最小值就可以往上传递,当第n次分割的数组有了minmax ,第n-1次也就有了minmax......最后传入的没有被分割的arr也就有了最大最小值.
//最小值赋值
if (leftarr[0] > rightarr[0]) {
minmax[0] = rightarr[0];
} else {
minmax[0] = leftarr[0];
}
//最大值赋值
if (leftarr[1] < rightarr[1]) {
minmax[1] = rightarr[1];
} else {
minmax[1] = leftarr[1];
}
4.代码执行过程
假设传入一个数组,并传入gold调用他
int[] arr = {23, 44, 59, 55, 63, 3, 6, 43};