【问题标题】:Finding if the element exist in a given range查找元素是否存在于给定范围内
【发布时间】:2014-09-14 16:18:02
【问题描述】:

我有两个数组 AB。而且我必须找到数组C 所需的元素数量以适应特定长度。

Length = B[i]-A[i]

例如:

A[0] = 1    B[0] = 4
A[1] = 4    B[1] = 5
A[2] = 5    B[2] = 9
A[3] = 8    B[3] = 10
and 
C[0] = 4
C[1] = 6
C[2] = 7
C[3] = 10
C[4] = 2

答案是4

解释:

C[0] is falling in the range of (A[0],B[0]) and (A[1],B[1])
C[1] is falling in the range of (A[2],B[2]) 
C[2] is of no use
C[3] is falling in the range of (A[3],B[3])
so the total is 4

我的方法:
传统方法:简单循环数组AC 的每个元素,如果在该范围内找到,则将A[i]B[i] 的值设置为减去无穷大或删除它们(对于 Arraylist)。

  • 时间复杂度是一个问题,所以不是一个好方法。

HashTable:将值存储在哈希表中,A[i] 作为键,B[i] 作为值。然后找到给定C[i] 的元素并删除键。我认为这不是一个好方法

请为此提供一个有效的算法。

【问题讨论】:

  • 你可以多次使用同一个范围吗?
  • @Dici 你能解释一下我没有得到你
  • 例如,如果 C[1] 为 3,即使 range (A[0],B[0]) 已经用于 C[0],你能用它吗?
  • 如果您能区分概念和实现,这将有助于使问题易于理解。数组是具有order 的东西。在您的情况下,间隔和点没有顺序。您有一个 set 间隔(带有起点和终点)和一组点。用数组实现集合很好,但这与您的问题完全无关。

标签: java arrays algorithm


【解决方案1】:

如果输入范围已经从小到大排序(B[i]

int bottomRangeIndex = 0;
int topRangeIndex = numberOfABRangesYouHave - 1;
int answerCounter = 0;

C.sort(); // Sort C so that it goes from smallest to largest number.

for number in C: {
    if (number < A[bottomRangeIndex]) {
        continue;
    } else if (number > B[topRangeIndex]) {
        return answerCounter;
    } else {
        while ((number > B[bottomRangeIndex++]) && (bottomRangeIndex <= topRangeIndex)) {
            // Just keeps incrementing bottomRangeIndex.
        }
        if (bottomRangeIndex > topRangeIndex) {
            return answerCounter;
        } else {
            answerCounter++;
            bottomRangeIndex++;
        }
    }
}

这可能有一些我没有想到的错误,但基本上它的作用是:

  1. C 类。我知道你说你不能这样做,但我不明白为什么,除非这是一个家庭作业问题。
  2. 如果 C 中的数字完全超出这些范围,则跳过检查 A、B 范围内的任何内容。如果当前数字大于 A,B 范围内的最大数字 (B[topRangeIndex]),则返回当前答案计数器,因为 C(已排序)中的其他元素不能再次位于 A,B 范围内。
  3. 由于 C 已排序并且当前数字大于所有 A、B 范围的底部元素,因此开始检查 C 中的数字是否落在每个 A 范围的 B 端。被检查的数字始终是 C 中的最小元素,因此如果它未能落入 A 范围的 B 端,则不应再次检查 A,B 范围,因此 bottomRangeIndex 会递增。
  4. 如果每个范围都已被 while 循环消除,我们就完成了检查(C 中的当前元素大于任何 A、B 范围中的最大数字,我们不需要检查其他任何内容。
  5. 如果正在检查的 C 中的数字不大于 A、B 范围末尾的数字(位于 bottomRangeIndex),则 A、B 范围包含来自 C 的元素。我们增加答案计数器,移动bottomRangeIndex 向上,然后继续。

试试这个,看看它是否有效。如果这是家庭作业,而您确实无法对 C 进行排序,那么您可以对其进行修改以通过少量调整为您提供正确的答案,但我不会说如何...

【讨论】:

  • 您的假设B[i] &lt;= A[i+1] 不成立。 OP 中明确指出间隔可能重叠。
  • 是的,刚刚注意到,当我通读并假设范围不会重叠时,我错过了 A[3]。也就是说,OP 确实令人困惑和模糊,所以我可能不会尝试改进这一点,除非 OP 可以更清楚地解释问题(比如为什么 C '无法排序')。我认为基于 OP 的其他问题,无论如何,他们只是希望我们做他们的功课。 :P - 希望我的回答能帮助有类似问题的人,就好像我的假设是真的一样,我认为这将是一个相当可靠的算法。
  • 没错,问题应该已经被细化,而不是只有一些 cmets 再次评论......
【解决方案2】:

好吧,根据你的回答,我们别无选择,只能对照A和B检查C的每个元素。但是由于A和B是升序的,所以性能应该是合理的:

    int len = A.length;
    boolean[] eliminated = new boolean[len]; // initially all elements are false
    int totalEliminated = 0;

    for (int i = 0; i < C.length; i++) {
        int c = C[i];
        for (int j = 0; j < len && A[j] <= c; j++) {
            if (B[j] >= c && !eliminated[j]) {
                System.out.println(c + " eliminates " + A[j] + " - " + B[j]);
                eliminated[j] = true;
                if (++totalEliminated == len) {
                    return i+1;
                }
            }
        }
    }
    return 0;

【讨论】:

  • 添加了 return 0 表示我们已经遍历了 C 的所有元素,但还没有设法消除所有 A/B 范围
  • 第一个(内部)循环可能会通过转换为二进制搜索而变得更快,我现在可能会这样做......
  • 抱歉,我的第一次尝试完全错误。我现在已经修复了代码。即使没有二进制搜索,性能似乎也不错。我敢肯定你可以用哈希表等做一些聪明的事情,但试试吧,让我知道你的想法。
【解决方案3】:

这是使用 ArrayLists 的更高效的版本:

        int len = arrA.length;
        ArrayList<Integer> A = new ArrayList<Integer>(len);
        ArrayList<Integer> B = new ArrayList<Integer>(len);
        for (int i=0; i<len; i++) {
            A.add(arrA[i]);
            B.add(arrB[i]);
        }

        for (int i = 0; i < C.length; i++) {
            int c = C[i];
            int j = 0;
            while (j<A.size() && A.get(j) <= c) {
                if (B.get(j) >= c) {
                    A.remove(j);
                    if (A.isEmpty()) return i+1;
                    B.remove(j);
                }
                else {
                    j++;
                }
            }
        }
        return 0;

【讨论】:

  • 我不认为二次方是你能做的最好的。
【解决方案4】:

这是在 O(n log n) 中解决它的一个快速草图。这可能不是实践中的最佳方法,但只是为了提供 n log n 方法。

总而言之,这是一种扫线技术。或者更确切地说,在这种情况下是一个全面的观点。

1. Sort arrays A, B, and C (cost: n log n). Think of the arrays as queues
   (that is, "remove" elements from the left by increasing a start index).
2. Create current-intervals set (initially empty. Has O(log n) operations.)
2. While A not empty or B not empty or C not empty:
3.   get the lowest element from the first (if any) elements in A, B, and C.
4.   if it's an A:
5.     Add the corresponding interval to the current-intervals list
6.   else if it's a B:
7.      Remove the corresponding interval from the current-intervals list
8.   else it must be a C, so:
9.      The answer to the query corresponding to C is the current-intervals list
        (in the current state)

【讨论】:

  • 天啊,他们又做到了。 -1。为什么?这真的让我望而却步。我有足够的信心说这不是一个糟糕的答案。
  • 正如我所说,如果你对 C 进行排序,那么你没有提供正确的答案
  • @Constantinos:如果是你,就不需要在这里投反对票。 OP对此并不是很清楚。其他答案也没有被否决。我的回答为 OP 中指定的问题本身提供了一个实际上有效的解决方案(而不是在巨大的 cmets 列表中以一种非常不清楚的方式)。
【解决方案5】:
for(int i =0 ;i<C.length;i++)
for(int j=0;j<A.length;j++)
{
    if(A[i]<=C[i] && B[i]>=C[i])
   {   answer++;
       A[i] = Integer.Max_Value;
     }
}

它会 给你一个正确的答案

【讨论】:

    【解决方案6】:

    我尝试了一些树结构,但最终我回到了简单的二进制搜索,所以现在是 O(nlogn):

    static int getAnswerV2a(int[] A, int[] B, int[] C) {
        int len = A.length;
        ArrayList<Interval> intervals = new ArrayList<Interval>(len);
        for (int i=0; i<len; i++) {
            intervals.add(new Interval(A[i], B[i]));
        }
    
        for (int i = 0; i < C.length; i++) {
            int c = C[i];
            binarySearch(intervals, 0, intervals.size(), c);
            if (intervals.isEmpty()) return i+1;
        }
        return -1;
    }
    
    static class Interval {
        int start, end;
    
        Interval(int start, int end) {
            this.start = start;
            this.end = end;
        }
    
        boolean matches(int c) {
            return start <= c && c <= end;
        }
    }
    
    // Find an interval (between indices i and j) that matches c
    // When found, remove it from the List and adjust indices accordingly
    static void binarySearch(ArrayList<Interval> intervals, int i, int j, int c) {
        if (i==j)
            return;
        else if (i+1==j) {
            if (intervals.get(i).matches(c))
                intervals.remove(i);
        }
        else {
            int mid = (int) Math.floor((i+j) / 2);
            Interval interval = intervals.get(mid);
            if (interval.start > c)
                binarySearch(intervals, i, mid, c);
            else if (interval.end < c)
                binarySearch(intervals, mid+1, j, c);
            else {
                intervals.remove(mid);
                binarySearch(intervals, i, j-1, c);
            }
        }
    }
    

    【讨论】:

    • 注意:我假设间隔按 A 和 B 的升序排序,即if A[i]==A[i+1] then B[i]&lt;B[i+1]。如果不是这种情况,那么它只需要一些(相当简单的)代码来对 B 值进行排序。
    猜你喜欢
    • 1970-01-01
    • 2013-09-09
    • 2014-12-05
    • 2016-11-07
    • 1970-01-01
    • 2020-10-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多