【问题标题】:Time Complexity: 3Sum algorithm under cubic time?时间复杂度:立方时间下的 3Sum 算法?
【发布时间】:2019-03-09 08:37:00
【问题描述】:

如何利用二分搜索来提高我的算法时间复杂度?

我正在审查一些面试的时间复杂度,但我无法让我的算法更省时。这是我对 3-Sum 问题的强力解决方案:有多少个三元组总和正好为 0?背景:我没有 CS 学位。

//BRUTE FORCE SOLUTION: N^3
var threeSum = function(list){
  var count = 0;

  //checking each triple
  for(var i = 0; i < list.length; i++){
    for(var j = i+1; j < list.length; j++){
      for(var k = j+1; k < list.length; k++){

        if(list[i] + list[j] + list[k] === 0){count++;}
      }
    }
  }
  return count;
};

//binary search code
var binarySearch = function(target, array){
  var lo  = 0;
  var hi  = array.length - 1;
  //base case
  while(lo <= hi){
    var mid = Math.floor( lo + (hi - lo) / 2 );
    if(target === array[mid]) return mid;
    if(target < array[mid]){
      hi = mid - 1;
    }
    if(target > array[mid]){
      lo = mid + 1;
    }
  }
  // value not found
  return -1;
}

我正在复习普林斯顿大学的在线算法课程,教授指出,使用二分搜索算法可以提高该算法的效率。

根据教授的说法,我们会:

  • 对列表进行排序
  • 对于每对数字 array[ i ] & array[ j ] 二分查找 -(array[ i ] + array[ j ])

但是,我无法理解二进制搜索是如何解决问题的。这是讲座中的一张幻灯片,我仍在努力理解,但可能对其他人有用:

我确信那里有几种有效的解决方案:请随时加入您的实施,因为它可能对我和其他未来的读者有所帮助。谢谢

【问题讨论】:

  • 条件list[i] + list[j] + list[k] === 0 等价于(或多或少)list[k] === -(list[i] + list[j]),这使得蛮力解决方案的k 循环成为线性搜索,将被二分搜索取代。

标签: javascript algorithm time-complexity binary-search


【解决方案1】:

但是,我无法理解二进制搜索是如何解决问题的。

这就是 n^2 log(n) 算法的工作原理:

  1. 在 O(nlogn) 时间内对列表进行排序
  2. 查找所有数字对(i,j),运行时间为 O(n^2)。
  3. 然后,对于每一对 (i,j),它会找到一个数字 k,其中 k = sum - j - i。这是常数时间 O(1)
  4. 该算法检查每个k 是否存在,因为元组(i,j,k) 的总和为sum。为此,请执行 二分搜索,这需要 log(n) 时间。

最终的运行时间为 O(nlogn) + O(logn * n^2) = O(n^2logn)

另一种(更快)的解决方案是用哈希表替换排序部分。然后,查找值 k 将花费 O(1) 时间而不是 logn

【讨论】:

  • 如果数组包含重复,您的哈希表解决方案是否仍然有效?即:[-1,-1,0]
【解决方案2】:

二分搜索方法试图解决的问题是将三次算法(这是您的蛮力算法)的复杂度降低为 ~ N^2 log N 算法。

正如其他评论者指出的那样,我们知道当以下语句:list[i] + list[j] + list[k] == 0 是 true 时,我们发现了 3SUM 结果。这与说-(list[i] + list[j]) == list[k] 相同。因此,该算法的目标是检查每个i 索引和j 索引对是否存在满足前面等式的对应k 索引。二进制搜索可以在 ~log N 时间内找到那些 k 索引。因此,总体增长顺序为 ~N^2 log N(外部 for 循环对应于 N^2 部分)。

至于 javascript 中的实现,我会这样做:

var threesum = function(list) {
  list.sort(function(a,b){return a - b});
  console.log(list);
  var cnt = 0;
  for(var i=0; i<list.length; i++) {
    for(var j=i+1; j<list.length; j++) {
      var k = bsearch(-(list[i]+list[j]), list);
      if (k!= null && k > j) {
        console.log("[i=%d], [j=%d], [k=%d]", i,j,k);
        cnt++;
      }
    }
  }
  return cnt;
};

var bsearch = function(key, a) {
  var lo = 0;
  var hi = a.length-1;
  while (lo <= hi) {
    var mid = lo + Math.floor((hi - lo) / 2);
    if (a[mid] < key) {
      lo = mid + 1;
    } else if (a[mid] > key) {
      hi = mid - 1;
    } else {
      return mid;
    }
  }
  return null;
};

threesum([41, 48, 31, 32, 34, 38, 1, -9, 12, 13, 99, 5, -65, 8, 3, -3])

【讨论】:

    【解决方案3】:

    算法基本上是这样工作的:

    • 对数组进行排序(最坏情况O(n ^ 2),取决于排序算法)
    • 生成所有数字对 - 接受O(n ^ 2)
    • 对于每一对(i , j),可能存在k,这样0 = i + j + k.kis simply-(i + j), thus we can easily look it up by binary search inO(log n). Cases where i

    因此总时间复杂度为O(n ^ 2 log n)。

    【讨论】:

      【解决方案4】:

      const threeSum =(array,target)=>{
        
        let result =[]
        
         array = array.sort((a,b)=> a-b)
        
        for(let i=0; i < array.length-2; i++){
          
          let left = i+1;
          let right = array.length -1;
          
          while(left < right){
            
            let sum = array[i]+ array[left]+ array[right];
            
            if(sum === target){
              result.push([array[i],array[left], array[right]]);
              
              left++;
              right--
            }else if(sum < target){
              
              //sum is lower than target so increment left pointer 
              left++;
            }else if(sum > target){
              //sum is greater than target so increment right pointer 
              right--;
            }
          }
          
          
        }
        //return the list 
        return result;
      }
      
      let a = [12, 3, 1, 2, -6, 5, -8, 6];
      console.log(threeSum(a, 0));
        Time Complexity: O(n^2) 
        Space Complexity: O(1)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2019-12-29
        • 1970-01-01
        • 1970-01-01
        • 2012-05-09
        • 1970-01-01
        • 1970-01-01
        • 2017-06-04
        • 1970-01-01
        相关资源
        最近更新 更多