下面,我设计了一个函数tournamentTreeKSelection
,它使用数组模拟树状结构,并返回数组中最大的元素。例如,给定输入数组[10,9,8,7,6,5,4,3,2,1]
,执行以下步骤以返回10.
[10, 8, 6, 4, 2, -1]
[10, 6, 2, -1]
[10, 2]
[10] //Max element of array found
我的目标是现在添加第二个参数int k
,请求函数返回第k个最大元素,使tournamentTreeKSelection(data, 2)
返回9。
我在修改算法以执行此任务时遇到了很多困难,因为我的假设是我必须跟踪max元素跳过的所有元素?任何帮助表示赞赏。
import java.util.ArrayList;
import java.util.Arrays;
public class TournamentTree {
public static int tournamentTreeKSelection(int[] data, int k) {
ArrayList<Integer> list = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
for(int i = 0; i < data.length - 1; i += 2) {
list.add(max(data[i] , data[i + 1]));
}
for(int i = 0; i < data.length - 1; i++) {
list2.add(min(data[i], data[i + 1]));
}
if(list.size() == 1) return list.get(0);
if(list.size() % 2 != 0) list.add(-1);
if(k == 1) return tournamentTreeKSelection(listToArray(list),k);
else return tournamentTreeKSelection(listToArray(list2), --k);
}
public static int max(int a, int b) {
return a > b ? a : b;
}
public static int min(int a, int b) {
return a > b ? b : a;
}
public static int[] listToArray(ArrayList<Integer> arr) {
int[] arr2 = new int[arr.size()];
for(int i = 0; i < arr.size(); i++)
arr2[i] = arr.get(i);
return arr2;
}
}
我现在修改了代码,但它只适用于k = 1 - 8,为什么它会崩溃? tournamentTreeKSelection(data,9)和tournamentTreeKSelection(data,10)返回3,它们应分别返回2和1。
答案 0 :(得分:2)
如果列表的大小为2或3,即使K > 1
,您的语句min(data[i], data[i + 1])
也会为真。
你为什么要[10,1,9,2,8,3,7,4,6,5]
,我觉得你只想删除最大元素,但案例是什么
[1,1,2,2,3,3,4,4,5]
,在1次迭代后Math.max
删除可能的结果9,8,7和6。
Math.min
,ArrayList
k==1
,这会给您带来很多开销。只需创建一个结果大小的数组。对于((data.length+1)/2)
,data.length-1
其他K==1
您说您的锦标赛树结构是必需的,但您在代码中循环它,因为它是一个数组。为什么?你可以从1循环中的public static int find(int[] a, int k) {
int[] max = find(a, 0, a.length - 1, k);
return max[k-1];
}
private static int[] find(int[] a, int lo, int hi, int k) {
if (hi < lo){
return new int[]{};
}
if(lo == hi){
return new int[]{a[lo]};
}
int mid = lo + (hi - lo) / 2;
int[] left = find(a, lo, mid, k);
int[] right = find(a, mid + 1, hi, k);
return merge(left, right, k);
}
private static int[] merge(int[] left, int[] right, int k) {
int[] res = new int[Math.min(k, left.length+right.length)];
int l = 0, r = 0;
for (int i = 0; i<res.length;i++) {
if (l == left.length)
res[i] = right[r++];
else if (r == right.length)
res[i] = left[l++];
else if (left[l] > right[r])
res[i] = left[l++];
else
res[i] = right[r++];
}
return res;
}
那一刻确定最大值,而不是一次性地取一半的最大值。
如前所述,可以使用排序方法或快速查找方法。我在想你怎么还能使用你的锦标赛树方法。我想出的最好的是合并排序是如何工作的。我稍微编辑了,因为你只需要返回最多K个元素。
{{1}}