【问题标题】:How do I use a recursive algorithm to determine whether the array contains two elements that sum to a given integer?如何使用递归算法来确定数组是否包含两个总和为给定整数的元素?
【发布时间】:2014-02-12 21:37:08
【问题描述】:

好的,谢谢大家的帮助!特别感谢@pjs 让我知道如何去做。这是我的新代码,但由于某种原因,它不会达到基本情况之一。抱歉,如果我删除了旧代码,这是我第一次在这里发布,我不确定是否应该用新代码回答我自己的问题。

//initialized int start = 0
//initialized int end = length of the array
//here goes the constructor

public boolean kPairSum(Integer k) {
        if (sortedIntegerArray.length < 2) {      //if array is less than two return false
            return false;
        }
        else if (start == end) {                  //once the start and the end meets. This is the base case that doesn't seem to work for me.
            return false;
        }
        else {
            int currentStart = sortedIntegerArray[start];   //get first int in the array
            int currentEnd = sortedIntegerArray[end-1];     //get the very last int in the array
            int sum = currentStart + currentEnd;            //get the sum 

            if (k.equals(sum)) {                            //compare sum and k if equal
                return true;
            }
            else if (sum <k) {                              //if sum is less than k then increment value of start
                start++; 
                return kPairSum(k);
            }
            else if (sum > k) {                             //if sum is greater than k then it decrements value of end
                end--;
                return kPairSum(k);
            }
            else {                                          //not sure if this is right, should I just get rid of the else if statement for sum > k and change it to just an else? I wrote this down cause it has to return a type of boolean.
                return kPairSum(k);
            }

        }

【问题讨论】:

  • 您“检查数组中每个可能的对”的方法不是 O(n) - 有 O(n^2) 个这样的对。 O(n)(平均情况)解决方案需要 O(n) 额外空间,使用哈希表
  • 乍一看,由于 if/else 语句,它永远不会调用您的递归函数 return kPairSum(k)。
  • @jrowe08 是的,我有一个不同的代码,它在 else 语句中进行了递归调用,但它一直给我一个 stackoverflow 错误,我认为这是因为我的基本情况无法访问所以我放弃了最后写了这样的代码:(
  • @user3303632 它永远不会调用 kPairSum 并且永远不会像现在的代码那样增加您的 x 变量
  • 没关系,我知道了,当我将 end 设置为长度时,我也立即减去了 1。因此,我只是将变量 end 放入 currentEnd 而不是 end-1。谢谢大家!

标签: java arrays algorithm set


【解决方案1】:

您的数组名为 sortedIntegerArray,但您似乎没有利用这一事实。

首先对数组的两端求和。如果总和小于k,则总和的两个元素之一必须更大。您只能通过增加较低的索引来获得更大的值,因为元素是有序的。同样,如果总和大于k,则两个元素之一必须更小,因此您需要减少上索引。在任何一种情况下,问题的结构都是相同的,但您现在正在对数组的子集进行操作,该子集由您递增/递减的索引指定。基本情况是您找到两个总和为k 的值,或者索引在某处相遇。递归应该跳出来。由于每次递归调用都会增加或减少边界索引,直到它们在中间相遇,所以它是 O(n)。

【讨论】:

  • 我现在才意识到你已经提到了它。谢谢你的主意!我会试试看能不能成功。
  • 感谢@pjs 真的帮助我理解了如何正确递归地编写代码
  • 我很高兴听到这有帮助。递归是一个发现过程,当你自己看到它时,你会学得最好。
【解决方案2】:

你的递归调用永远不会调用:

    if (sum == k) {                     //compare to given k
        return true;
    } else if (xx == sortedIntegerArray.length-1 ||  sum != k) {
        return false;
    }

请注意,您基本上有两种选择:sum==k,然后 - 返回 true,或 sum!=k - 然后返回 false。递归调用不可达。

使用哈希表可以实现O(n)(平均情况)解决方案。这个想法是在迭代时将每个元素添加到哈希表中,并检查是否存在完成到 k 的现有元素。

for each element e in arr:
   if e is in table:
       return true
   table.add(k-e)
return false //no pair was found that sums to k

检查所有对的递归解决方案基本上是类似于嵌套 for 循环的蛮力。

//i is the index we are now checking, b is a boolean indicating we have already reduced one element
    kSum(k,i,b):
      if i == arr.length
         return false
      if b == true && k == 0:
         return true
      if b == false:
         return kSum(k-arr[i],i+1,true) || kSum(k,i+1,false)
      else:
         return kSum(k,i+1,b)

【讨论】:

  • 及其变体,如果您需要返回构成总和而不是布尔值的数组元素?
  • @user1988876 在这种情况下,您使用Map&lt;Integer,Integer&gt;(而不是哈希表的集合语义) - 其中值是导致新插入的索引。一旦你发现解决方案应该是正确的,你就有了两个索引(迭代时一个在手边,另一个来自地图)并且解决方案很简单。
  • +1是的,有道理;上面已经很好地解释了您使用表的逻辑,但是递归的逻辑缺乏解释;特别是对于最后两个返回语句..
  • @user1988876 这基本上是递归调用的蛮力工作人员。如果你还没有选择一个数字——你可以“选择”这个数字,或者不选择它,如果你已经选择了一个数字——你必须继续(直到你遇到一个停止子句)。
  • 您错过了一个事实,扣除的列表也已排序,并且很容易找到 O(n) 的匹配项。我不知道如何在评论中编写代码,所以我再发布一个答案。
【解决方案3】:

我在这里有两个实现: 我最初开始工作并使用 Amit 的回答,我进一步改进了它。 prints/returnindices 也构成了 sum。适用于 O(n) 中的已排序和未排序数组。当然,这不是recursive

    public static void sumArray2(int[] arr, int sum){
        Map <Integer, Integer> map = new HashMap<>();
        for (int i=0; i < arr.length;i++){
            map.put(arr[i], i);
        }
        for (int i =0; i < arr.length;i++){
            int diff = sum-arr[i];
            if (map.containsKey(diff) && i!=map.get(diff)) {
                System.out.printf("The two indices are %s and %s%n ",i,map.get(diff));
                return ;
            }
        }
        System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
        return ;
    }

    //returns a boolean if sum could be formed.
        public static boolean sumArray3(int[] arr, int sum){
            Map <Integer, Integer> map = new HashMap<>();
            for (int i =0; i < arr.length;i++){
                int diff = sum-arr[i];
                if (map.containsKey(arr[i])) {
                    System.out.printf("The two indices are %s and %s%n ",i,map.get(arr[i]));
                    return true;
                }
                map.put(diff,i);
            }
            System.out.printf("The sum:%s cannot be formed with given array:%s",sum,Arrays.toString(arr));
            return false;
        }

【讨论】:

  • 我已经尝试过这种方式,但遗憾的是我必须使用递归来实现它:(
【解决方案4】:

不知道如何添加格式化评论,所以这里是增强版,比 Amit 提供的,使用 O(n) :)

def check(source, need):
  target = [need-i for i in source]
  target.reverse()
  i = 0
  j = 0
  # walk thru lists same "merge" to find a match
  for i in xrange(0, len(source)):
    while j < len(target) and source[i] > target[j]:
      j=j+1
    if i != len(source)-j-1 and j < len(target) and source[i] == target[j]:
      return True
  return False

【讨论】:

    猜你喜欢
    • 2012-09-28
    • 2019-04-04
    • 2012-02-21
    • 2023-03-21
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 1970-01-01
    • 2012-12-05
    相关资源
    最近更新 更多