我正在尝试找出算法来实现一种方法,在这方面我需要一些建议。我给出了一个数组和范围,
A = [1, 15, 30, 40, 50]
range = 10
我需要找出可以覆盖给定数组所有数字的最小点数。
覆盖意味着您可以在提供的范围内同时达到左右两个距离。例如,如果我的点位于23且范围为5,那么我可以到达18-23左侧和23-28右侧。这些点可以覆盖给定范围的左侧和右侧。
在提供的数组中,结果为3。我们需要在1处一个点,在15处需要一个点,在40处需要第三个点。我在下面解释,
i. The point at 1 will cover till 10 (1-10)
ii. The point at 15 will cover itself (15)
iii. The point at 40 will cover left till the 30 and at the right till the 50 (30-40-50)
请先提供充分的理由,然后再尝试投票。谢谢。
答案 0 :(得分:1)
如果有时间,我将尝试使用Stream API使其简洁:-
public static void main(String[] args) {
int[] arr = {1, 15, 30, 40, 50};
int range = 10;
Map<Integer, Set<Integer>> map = new HashMap<>(arr.length); //maps indexes of elements to the indexes of elements it covers
for (int i = 0; i < arr.length; i++) {
for (int j : arr) {
if (j >= arr[i] - range && j <= arr[i] + range) {
if (map.get(i) == null) {
Set<Integer> set = new HashSet<>();
set.add(j);
map.put(i, set);
} else {
map.get(i).add(j);
}
}
}
}
Set<Integer> mapEntriesToDelete = new HashSet<>();
for (Map.Entry<Integer, Set<Integer>> e : map.entrySet()) {
for (Map.Entry<Integer, Set<Integer>> f : map.entrySet()) {
if (!e.getKey().equals(f.getKey()) && e.getValue().containsAll(f.getValue())) {
mapEntriesToDelete.add(f.getKey());
}
}
}
mapEntriesToDelete.forEach(map::remove);
System.out.println("Points: " + map.size());
System.out.print("At indexes: ");
map.keySet().forEach(k -> System.out.print(k + ","));
}
输出
Points: 3
At indexes: 0,1,3,
答案 1 :(得分:1)
如果对数组排序,则可以使用贪婪算法。我还假设输入中的所有数字均为正。
请考虑以下步骤:
1. Int cover = -1, points= new array
2. For each element in the array:
2.1 . If element > cover then:
2.1.1 cover = element + range - 1 // biggest value that still cover the element
2.1.2 push to point cover value
points数组将包含在给定范围内覆盖该数组所需的最小点数
复杂度:假设n是输入数组的大小:
如果对数组排序,则时间复杂度为O(n),否则为O(nlogn)。当k为以n为边界的覆盖点数时,空间复杂度为O(k)。如果只需要点数,则空间复杂度为O(1)
如果只能从数组中选择点,则可以如下修改算法:
1. Int cover = -1, points= new array
2. For each i in the array.length:
2.1 If array[i] > cover then:
2.1.1 cover = array[i] //element can cover itself
2.1.2 for (j=i+1; array[j] < array[i] + range; j++) // find the largest element who still cover array[i]
2.1.2.1 cover = array[j] // element in index j cover also index i
2.1.3 push to point cover value
2.1.4 add range to cover // to mark for cover after a[j]
空间复杂度相同。时间复杂度也为O(n)-因为内部循环(j)的每个步骤都在执行i循环,所以我们无法通过if语句的条件-因此我们停留在O(n)。
答案 2 :(得分:0)
我对David在较早答案中提出的算法进行了编程。下面提供了代码,
public static int getMinNumberOfPoints(int R, int[] A) {
int cover = -1;
int N = A.length;
List<Integer> list = new ArrayList<>();
int count = 0;
for (int i = 0; i < N; i++) {
if (A[i] > cover) {
cover = A[i];
/*
* find the largest element who still cover A[i]
* */
for (int j = i + 1; j < N && A[i] + R >= A[j]; j++) {
cover = A[j];
}
/*
* add the cover to keep track for camera placement
* */
list.add(cover);
count++;
cover += R;
}
}
return count;
}