【问题标题】:How can I find two elements in an array that sum to k如何在数组中找到两个总和为 k 的元素
【发布时间】:2011-12-04 06:00:11
【问题描述】:

假设给定一个未排序的整数数组

A = {3,4,5,1,4,2}

输入:6 输出:{5,1}, {4,2}

如何在 O(n) 或 O(log n) 中做到这一点。任何建议将不胜感激。

更新: 我们能写出比这更高效的东西吗?

for(int i=0;i<array.length-1;i++)  
{  
    if(array[i]+array[i+1]==6)  
        System.out.println("{"+array[i]+","+array[i+1]+"}");  
}  

【问题讨论】:

  • [给定两个数组 a 和 b 的可能重复项。找到所有元素对 (a1,b1),使得 a1 属于数组 A,b1 属于数组 B,其和 a1+b1 = k] (stackoverflow.com/questions/3815116/…)
  • 在您的示例中,您假设两个整数是相邻的。这是故意的吗?对于k=6,如果A={2,3,4},即使{2,4}=6,也不会返回任何内容。此外,您的算法是 O(n),因此无法编写更高效的算法 - 但可以编写更正确的算法。

标签: java arrays


【解决方案1】:

如果存储在输入数组中的数字只是正数,那么我将创建另一个包含 k+1 个 ArrayList 元素的数组 K。其中 k 是您需要它们相加的数字。 只有两个小于 k 的数字可以加起来为 k(假设我们处理正整数)或特殊情况下的 {0,k}。 然后我将遍历输入数组的所有元素,对于每个小于或等于 k ​​的 int m,我将获取它的索引并将该索引添加到索引 m 处的 ArrayList K 的数组中。 然后我将遍历数组 K 的前半部分,对于每个索引 i ,其中存储了一些整数,我会找到互补索引 [k-i] 并查看其中是否有任何值。如果有,那么这些就是你的配对。 顺便说一句,这是 O(n)。

public static void findElemtsThatSumTo( int data[], int k){
    List arrayK[]= new List[k+1];
    for(int i=0; i<arrayK.length; i++)
        arrayK[i]= new ArrayList<Integer>();

    for(int i=0; i<data.length; i++){
        if(data[i]<=k)
            arrayK[data[i]].add(i);
    }

    for(int i=0; i<arrayK.length/2; i++){
        if(!arrayK[i].isEmpty() && !arrayK[k-i].isEmpty())
        {
            for(Object index: arrayK[i])
                for(Object otherIndex: arrayK[k-i])
                    System.out.println("Numbers at indeces ["+index.toString()+", "+otherIndex.toString()+"] add up to "+k+".");
        }
    }

}

【讨论】:

  • 感谢您的详细解决方案。在这个数组输入 {6,4,5,1,4,2,0} 我得到的答案是 Numbers at indeces [6, 0] add up to 6. Numbers at indeces [3, 2] add up to 6. Numbers at indeces [5, 1] add up to 6. Numbers at indeces [5, 4] add up to 6. 有什么问题吗?
  • 这些是 ineces,而不是值。你的数组索引是从零开始的,所以索引 5 处的项目是整数 2,索引 4 处的项目是整数 4,所以 2+4 是 6。一切似乎都还好。您可以将该 println 语句转换为打印值而不是索引,但索引更有用(IMO),因为您可以在许多不同的索引处使用相同的数字。
【解决方案2】:

与您的其他问题一样,O(log n) 是不可能的,因为您必须检查整个数组。但是 O(n) 或多或少是可能的。

如果你的可能整数范围相对较小——也就是说,如果它在 n 的常数因子内——那么你可以这样写:

final boolean[] seen = new boolean[max - min + 1];
for(final int a : A)
{
    if(seen[input - a - min])
        System.out.println("{" + (input - a) + "," + a + "}");
    seen[a - min] = true;
}

如果没有,您可以做同样的事情,但使用 HashSet&lt;Integer&gt; 而不是数组:

final Set<Integer> seen = new HashSet<Integer>();
for(final int a : A)
{
    if(seen.contains(input - a))
        System.out.println("{" + (input - a) + "," + a + "}");
    seen.add(a);
}

但这不会有保证 O(n) 时间。

【讨论】:

  • 你能解释一下 HashSet 方法有什么问题,因为你说它不能保证 O(n) 时间。
【解决方案3】:
public static void main(String[] args) {
    // TODO Auto-generated method stub

    int arr[]={4,2,6,8,9,3,1};
    int sum=10;
    int arr1[]=new int[sum];


    for(int x=0;x<arr.length;x++)
    {
        arr1[arr[x]]++;
    }

    for(int y=0;y<arr.length;y++)
    {
        if(arr1[sum-arr[y]]==1)
        {
            System.out.println(arr[y]+","+(sum-arr[y]));
        }
    }

}

【讨论】:

  • 您能否解释一下这如何回答问题,或者更有效?
【解决方案4】:

我对 O(n) 复杂度和 O(n) 额外内存的这个问题的小回答。此代码 sn-p 返回总和为 K 的所有唯一索引元素对。

/**
 * Returns indices of all complementary pairs in given {@code arr} with factor {@code k}. Two elements {@code arr[i]} and {@code arr[j]} are
 * complementary if {@code arr[i] + arr[j] = k}.
 * Method returns set of pairs in format {@literal [i,j]}. Two pairs {@literal [i,j]} and {@literal [j,i]} are treated as same, and only one pair
 * is returned.
 * Method support negative numbers in the {@code arr}, as wel as negative {@code k}.
 * <p>
 * Complexity of this method is <t>O(n)</t>, requires <t>O(n)</t> additional memory.
 *
 * @param arr source array
 * @param k   factor number
 * @return not {@code null} set of all complementary pairs in format {@literal [i,j]}
 */
public static Set<String> getComplementaryPairs(int[] arr, int k) {
    if (arr == null || arr.length == 0)
        return Collections.emptySet();

    Map<Integer, Set<Integer>> indices = new TreeMap<>();

    for (int i = 0; i < arr.length; i++) {
        if (!indices.containsKey(arr[i]))
            indices.put(arr[i], new TreeSet<>());
        indices.get(arr[i]).add(i);
    }

    Set<String> res = new LinkedHashSet<>();

    for (Map.Entry<Integer, Set<Integer>> entry : indices.entrySet()) {
        int x = entry.getKey();
        int y = k - x;

        if (x == y) {
            int size = entry.getValue().size();

            if (size < 2)
                continue;

            Integer[] ind = entry.getValue().toArray(new Integer[size]);

            for (int j = 0; j < size - 1; j++)
                for (int m = j + 1; m < size; m++)
                    res.add(String.format("[%d,%d]", ind[j], ind[m]));
        } else if (x < y && indices.containsKey(y))
            for (int j : entry.getValue())
                for (int m : indices.get(y))
                    res.add(String.format("[%d,%d]", j, m));
    }

    return res;
}

【讨论】:

    猜你喜欢
    • 2011-08-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-18
    • 2016-05-14
    • 2013-01-12
    • 1970-01-01
    相关资源
    最近更新 更多