【问题标题】:Finding a case when binary search fails寻找二分查找失败的案例
【发布时间】:2016-11-18 22:43:55
【问题描述】:

我正在尝试解决一个非常有趣的编程挑战,但我有点不知道为什么我的代码会失败。这里是:

写一个函数,给定一个列表和一个目标总和,返回 总和等于的任何两个不同元素的从零开始的索引 目标总和。如果没有这样的元素,函数应该 返回空值。 例如, findTwoSum(new int[] { 1, 3, 5, 7, 9 }, 12) 应该返回以下任何索引元组:

1, 4 (3 + 9 = 12)
2, 3 (5 + 7 = 12)
3, 2 (7 + 5 = 12)
4, 1 (9 + 3 = 12)

应该很简单吧?所以这是我的功能:

public static int[] findTwoSum(int[] list, int sum) {
        int[] indices = null;
        for(int i = 0; i < list.length; i++) {
            int currentNum = list[i];
            int findNum = sum - currentNum;
            int length = list.length;
            int min = i;
            int max = length-1;
                        
            while(max >= min) {
                int guess = (max+min)/2;
                          
                if(list[guess] == findNum) {
                  return new int[] {i,guess};
                } 
                
                if(list[guess] < findNum) {
                    min = guess + 1;
                }
                
                if(list[guess] > findNum) {
                    max = guess - 1;
                }
            }
            
        }
       
        
        return indices;
    }

代码非常简单,对于数组中的每个元素,它会尝试使用二进制搜索找到另一个元素,以便它们的总和等于提供的sum。我已经测试了这段代码,但我找不到失败的场景,假设提供的数组已排序。但是,当我在 TestDome 上运行此代码时,最后一种情况失败了,这是某种错误的解决方案。有人能指出这种方法有什么问题吗?

【问题讨论】:

  • 该问题要求列表的两个 distinct 元素,您的代码似乎无法正确处理。
  • @Gassa 是的,我也有检查过,它真的没有帮助。我现在在想的是,可能是数组在最后一种情况下没有排序。
  • 给定的列表是否已经排序?
  • @User_Targaryen 我预计会这样,但我可能错了。所以我想我需要先对其进行排序并跟踪原始索引。
  • @Zed:那肯定是问题所在......

标签: java algorithm


【解决方案1】:

代码假定列表已排序。问题陈述没有说明元素的顺序,所以需要自己对数组进行排序。由于需要索引,因此需要对值和索引对进行排序。

更快的方法是将数据放入包含计数和原始索引的哈希映射中,并检查列表中每个n 是否存在Target - n。当Target 等于2*n 时,您需要对特殊情况进行计数。

【讨论】:

  • (A faster approach 比搜索所选数字和目标总和之间的差异) 更简单的方法将(二进制)搜索与第一个数字的差异,并从第一个索引开始,然后从找到的索引向下遍历,直到它们相遇(唯一对)或到达另一个索引的起点(如所述的问题/这部分是Targaryen's answer)。
【解决方案2】:

根据作者关于初始列表排序顺序的问题和澄清,似乎初始列表没有排序。所以需要对列表进行排序,原始索引需要单独存储在另一个列表中。

在对数组进行排序并记下原始索引之后,假设arr[] 包含排序列表,indices[] 包含arr[] 中相应元素的原始索引。简单来说,indices[i] 给出了元素 arr[i] 的原始索引。

现在您可以按照 2-SUM 算法来查找配对:

  • 初始化两个索引变量以找到候选 排序数组中的元素。

    • 首先初始化最左边的索引:l = 0
    • 初始化第二个最右边的索引:r = ar_size-1
  • 循环当 l

    • 如果 (arr[l] + arr[r] == sum) 则返回 pair(indices[l],indices[r])
    • 否则 if( arr[l] + arr[r]
    • 否则--
  • 整个数组中没有候选人 - 返回NULL

您也可以使用二进制搜索技术代替 2-SUM 过程。

希望对你有帮助!!

【讨论】:

    【解决方案3】:

    试试这个解决方案。它对数组进行排序并使用二进制搜索来定位第二个元素,该元素必须是 sum - n

    如果找到匹配对,则在原始数组中查找,以确定原始索引:

    public static int[] findTwoSum(int[] list, int sum) {
        int len = list.length;
        int[] sortedList= Arrays.copyOf(list, len);
        Arrays.sort(sortedList);
        for (int i = 0; i < len; i++) {
            int m = list[i];
            int j = Arrays.binarySearch(sortedList, sum - m);
            if (j >= 0 && i != j)
                return new int[] { i, findIndex(list, sortedList[j]) };
        }
        return null;
    }
    
    public static int findIndex(int[] list, int m) {
        int len = list.length;
        for (int i = 0; i < len; i++) {
            if (list[i] == m)
                return i;
        }
        return -1;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-12-10
      • 1970-01-01
      • 2019-03-19
      • 2012-03-25
      相关资源
      最近更新 更多