覆盖数组的给定范围

时间:2018-09-21 06:08:42

标签: java algorithm time-complexity space-complexity

我正在尝试找出算法来实现一种方法,在这方面我需要一些建议。我给出了一个数组和范围,

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)

请先提供充分的理由,然后再尝试投票。谢谢。

3 个答案:

答案 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;
}