【问题标题】:Most efficient way to find two integers that sum up to target value with specific conditions找到两个整数的最有效方法,这些整数在特定条件下总和为目标值
【发布时间】:2021-03-14 20:19:01
【问题描述】:

我正在寻找一种有效的方法来打印出在某些条件下总和为目标值的两个整数:

  • 第一个 int 应该小于第二个 int 对
  • 打印应该按对中的第一个升序进行

我编了一些意大利面条,在时间复杂度上似乎比两个循环更有效,但是,它不包括排序。目前我的想法已经用完了。

我的问题如下:

  1. 对输出进行排序的最佳方法是什么?
  2. 除了我目前的解决方案之外,还有其他方法可以提高时间复杂度吗?

PS。输入输出将是大量的整数,所以我想知道是否应该替换 System.out.println。

提前谢谢你。

编辑: 我必须打印出所有的配对。一个 int 可以是多对。输入可以增长到几十万个 int。

给定目标 12: 示例输入: 2 10 0 8 4 12 8

示例输出: 0 12 2 10 4 8 4 8

public static void myFindPair(int[] arr, int target) {

        // Key = difference, value = index
        Map<Integer, Integer> map = new HashMap();

        for (int i = 0; i < arr.length; i++) {
            int difference = target - arr[i];
            map.put(difference, i);
            System.out.print(arr[i]);
        }


        for (int i = 0; i < arr.length; i++) {
            if (map.containsKey(arr[i]) && map.get(arr[i]) != i) {
                int first = arr[i];
                int second = arr[map.get(arr[i])];
                if (first < second) {
                    System.out.println(first + " " + second);
                }
            }
        }
    }

【问题讨论】:

  • 你需要找到所有这样的对还是只找到一个?
  • 添加一些示例输入和输出。
  • 如果第一个 int 小于第二个 int,则这两个值按定义按升序排列,那么 2 个项目符号不只是在说同样的事情吗?
  • 请分享更多细节。你的代码有什么不工作的地方吗?
  • 请务必提及问题的约束。 数组的最大长度是多少?数组元素的最大大小是多少? 如果约束不是太大,你的问题可以在O(n) 中解决。如果它们足够大,O(n*log n) 是我所知道的最佳解决方案。

标签: java arrays algorithm


【解决方案1】:

首先对数组进行排序。如果arr 已排序并且arr[0] + arr[arr.length - 1] &gt; target,那么arr[arr.length - 1] 不可能是一对;您将其添加到尽可能小的值,但对于目标来说仍然太大。同样,如果arr[0] + arr[arr.length] &lt; target,那么arr[0] 不可能是一对的一部分。这导致了以下算法。

public /* return type */ findPair(int[] arr, int target)
{
  Arrays.sort(arr);

  int i = 0, j = arr.length - 1;
  
  while (i < j) {
    int sum = arr[i] + arr[j];
    if (sum < target) i++;
    else if (sum > target) j--;
    else {
      /* sum == target, so add arr[i] and arr[j] to a set of solutions. */
      /* I'm assuming that the elements of arr are unique. */
      i++;
      j--;
    }
  }

  return /* set of solutions */
}

【讨论】:

  • 此部分用于解答。这不是答案,而是对答案的暗示,因此应该是对问题的评论。
  • 谢谢你,@JeffC。我已经习惯了这里每个人做事的方式。给出答案不好吗?这感觉像是一道作业题。
  • 我也有同感。我认为这取决于你来决定。当我看到这样的事情时,我倾向于做你所做的,但把它放在评论中,这样我就可以希望引导人们找到正确的答案,而不是马上给他们答案。但是...我几乎可以保证,在 OP 有机会考虑您的指导并提出他们自己的答案之前,其他人只会回答。
  • 谢谢山姆,我真的很喜欢你的解决方案。但是在我的情况下,数组的元素不是唯一的,我会尝试根据我的需要调整您的解决方案。但是,我在尝试解决它时避免了排序位,以使整个任务的时间复杂度尽可能低。 (但不确定这是个好主意)。
  • 如果元素不是唯一的但数组已排序,您可以在下一个元素相等的情况下前进点。
【解决方案2】:

这是一个可能的解决方案您的问题:


使用计数排序

输入数组 A 的长度 = n

设输入范围,即数组的最大元素 = k

算法:

Store the frequency of each element of the array A.
Use the frequency array to find pairs.

示例:

A = 2 10 0 8 4 12 8 4

下面是对应的频率数组:

element:     0  1  2  3  4  5  6  7  8  9  10  11  12
frequency:   1  0  1  0  2  0  0  0  2  0  1   0   1

使用频率数组,我们可以轻松地按升序找到目标总和为T的对。

我们知道,如果 ab 是数组 A 的元素,其中 a b 然后它们就成对了,

a + b = T
b = T - a

使用这个,我们可以检查a的频率>0b的频率>0的频率,那么这样的一对是可能的。这样做我们可以在O(k) 中找到所有对,其中k = 输入范围

解决方案代码:

private static void printPair(int[] A, int targetSum)
{
    //find the maximum element
    int max = A[0];

    for (int element: A) max = Math.max(max, element);    

    //Make a frequency array
    int[] frequency = new int[max+1];
    for (int element: A) frequency[element]++;

    //Find pairs
    for (int i = 0;i < frequency.length/2;i++)
    {
        if (targetSum - i < 0) break;

        if (frequency[i] > 0 && frequency[targetSum-i] > 0)
        {
            while (Math.min(frequency[i], frequency[targetSum-i]) > 0)
            {
                System.out.print("Pair: " + i + "\t" + (targetSum - i));
                System.out.println();

                frequency[i]--;
                frequency[targetSum - i]--;
            }
        }
    }
}

里面还有一个while循环,因为如果数组ftimes中存在一对,我们需要打印它ftimes

如果您使用counting sort 的更好实现,我发布的解决方案可以得到改进。在我使用的解决方案中:

输入的范围,即数组的最大元素 = k

我是故意这样做的,因此解决方案更容易理解。但是,如果我们将范围更改为:

,解决方案会更有效:

新的输入范围,即数组的最大元素-数组的最小元素 = k

进行此更改也会使此解决方案适用于负数。

如果您使用此范围,则需要对解决方案进行一些更改,如果您能理解我提供的解决方案,那么这些更改并不难。 您只需要更改访问数组中每个元素的频率的方式。这是改进的计数排序的链接:https://www.geeksforgeeks.org/counting-sort/

解的时间复杂度:

该解决方案的时间复杂度为O(n+k)这可能看起来像一个线性时间复杂度。但是,这取决于输入。

假设:

A = 4 3 30 5 1

这里,

n = 5 
k = 30

k 几乎等于n^2。因此,解决方案的时间复杂度变为O(n + n^2) = O(n^2)所以时间复杂度严格取决于可能的输入类型。


希望我对你有所帮助。我没有详细介绍解决方案代码,因为这样做会使答案太长。但是,如果您无法理解解释、解决方案代码或者您还希望我发布第二个可能的解决方案,请发表评论。我很乐意为您提供帮助。

【讨论】:

    猜你喜欢
    • 2011-01-15
    • 1970-01-01
    • 2021-01-19
    • 2021-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多