【问题标题】:Maximum Length of Repeated Subarray (leetcode)重复子数组的最大长度(leetcode)
【发布时间】:2020-04-18 18:01:36
【问题描述】:

我正在查看此 leetcode question,但在完成天真的方法时遇到了问题。我能够找到最佳解决方案here。但我不确定我的幼稚尝试有什么问题。

问题如下:

给定两个整数数组 A 和 B,返回一​​个数组的最大长度 出现在两个数组中的子数组。

示例:
输入:A:[1,2,3,2,1] B:[3,2,1,4,7]

输出:3

解释:最大长度的重复子数组为[3, 2, 1]。

这是我当前的代码:

var findLength = function(a, b) {
    if (a.length === 0 || b.length === 0) {
        return 0;
    }
    
    let aWithoutFinalNumber = a.slice(0, a.length - 1);
    let bWithoutFinalNumber = b.slice(0, b.length - 1);

    let aFinalNumber = a[a.length - 1];
    let bFinalNumber = b[b.length - 1];
    
    // matching numbers
    if(aFinalNumber === bFinalNumber) {
        return 1 + findLength(aWithoutFinalNumber, bWithoutFinalNumber);
    } else { // mismatch. Compete to find the maximum length.
        return Math.max(findLength(a, bWithoutFinalNumber), findLength(aWithoutFinalNumber, b));
    }
};

我的解决方案通过了几个测试用例,但在 a: [0,1,1,1,1] b: [1,0,1,0,1] 这样的情况下失败了。对我的错误的任何见解将不胜感激!

【问题讨论】:

    标签: javascript algorithm dynamic-programming


    【解决方案1】:

    您可以使用嵌套循环,当两个数组中出现相同元素时,您可以开始递增这两个索引,直到两个数组中的元素相同。为您提供最大元素集的结果将是返回的结果。

    function maxSub(a, b) {
      let result = null;
    
      function findAll(i, j) {
        const res = [];
    
        if (a[i] !== b[j] || a[i] == undefined || b[j] == undefined) {
          return res;
        }
    
        return res.concat(a[i], ...findAll(i + 1, j + 1))
      }
    
      a.forEach((e, i) => {
        b.forEach((c, j) => {
          if (e == c) {
            const sub = findAll(i, j);
    
            if (!result || sub.length > result.length) {
              result = sub
            }
          }
        })
      })
    
      return result;
    }
    
    
    console.log(maxSub([0, 1, 1, 1, 1], [1, 0, 1, 0, 1]))
    console.log(maxSub([1, 2, 3, 2, 1], [3, 2, 1, 4, 7]))

    【讨论】:

      【解决方案2】:

      问题来自您计算最后一个元素匹配时的最大长度的方式。这是一个最小的例子:

      var findLength = function(a, b) {
          if (a.length === 0 || b.length === 0) {
              return 0;
          }
      
          let aWithoutFinalNumber = a.slice(0, a.length - 1);
          let bWithoutFinalNumber = b.slice(0, b.length - 1);
      
          let aFinalNumber = a[a.length - 1];
          let bFinalNumber = b[b.length - 1];
      
          // matching numbers
          if(aFinalNumber === bFinalNumber) {
              return 1 + findLength(aWithoutFinalNumber, bWithoutFinalNumber); //< -- problem here
          } else { // mismatch. Compete to find the maximum length.
              return Math.max(findLength(a, bWithoutFinalNumber), findLength(aWithoutFinalNumber, b));
          }
      };
      
      console.log(findLength([1, 0, 2, 1], [1, 0, 3, 1]));

      如果有任何匹配,您将1 添加到最大长度,但如果稍后出现不匹配,则不一定是这样。为了便于理解,这里是一个简略版本的插图:

      [1, 0, 2, 1]
                ^-------|
      [1, 0, 3, 1]      | -- match, max length +1
                ^-------|
      ______
      
      [1, 0, 2, 1]
             ^----------|
      [1, 0, 3, 1]      | -- mismatch, max length +0
             ^----------|
      
      ______
      
      [1, 0, 2, 1]
          ^-------------|
      [1, 0, 3, 1]      | -- match, max length +1
          ^-------------|
      
      ______
      
      [1, 0, 2, 1]
       ^----------------|
      [1, 0, 3, 1]      | -- match, max length +1
       ^----------------|
      

      当您汇总所有匹配项时,您会得到3,但是,当出现不匹配时,计数应该已重置。

      为了避免这个问题,可以对算法进行的一个简单更改是将当前计数作为参数传递给函数。这样,您可以控制何时需要重置计数:

      var findLength = function(a, b, maxSoFar = 0) { //<-- default count of zero
          if (a.length === 0 || b.length === 0) {
              return maxSoFar; //<-- return the count
          }
      
          let aWithoutFinalNumber = a.slice(0, a.length - 1);
          let bWithoutFinalNumber = b.slice(0, b.length - 1);
      
          let aFinalNumber = a[a.length - 1];
          let bFinalNumber = b[b.length - 1];
      
          // matching numbers
          if(aFinalNumber === bFinalNumber) {
              const newMax = maxSoFar + 1; //<-- increment the count
              return Math.max(newMax, findLength(aWithoutFinalNumber, bWithoutFinalNumber, newMax)); //<-- return the newMax in case the next is a mismatch
          } else { // mismatch. Compete to find the maximum length.
              return Math.max(findLength(a, bWithoutFinalNumber), findLength(aWithoutFinalNumber, b)); //<-- reset the count
          }
      };
      
      console.log(findLength([1, 0, 2, 1], [1, 0, 3, 1]));
      console.log(findLength([1, 2, 3, 2, 1], [3, 2, 1, 4, 7]));
      console.log(findLength([0, 1, 1, 1, 1], [1, 0, 1, 0, 1]));

      【讨论】:

      • 实际上你的解决方案不会通过这个测试用例 - ([0,0,0,0,0,0,1,0,0,0], [0,0,0,0 ,0,0,0,1,0,0]),正确答案是 9,您的解决方案输出 7。这是因为即使在这种情况下,当最后一个元素相同时,您也必须检查此结果 - @987654326 @。我建议使用 dp 来解决这个问题。
      • @alexnik42 同意这不是任何位置的任何子阵列的最佳解决方案。它只对直接匹配的索引进行线性扫描。但是,我在这里的重点是纠正 OP 当前的方法,对逻辑进行最小的更改,而不是解决 OP 的挑战。
      【解决方案3】:

      您也可以将 dp 与表格一起使用。我尝试了其他代码,它在以下情况下出现错误:[0,0,0,0,1,0,0] 和 [0,0,0,0,0,1,0]。 这是相同的python代码。

      def findLength(a, b):
          if len(a)==0 or len(b)==0:
              return 0
              
          n=len(a)
          m=len(b)
      
          dp=[[0 for _ in range(n+1)] for _ in range(m+1)]
          maxSoFar=0
             
          for i in range(1,m+1):
              for j in range(1,n+1):
                  if a[j-1]==b[i-1]:
                      dp[i][j]=dp[i-1][j-1]+1
                      maxSoFar=max(maxSoFar,dp[i][j])
                  else:
                      dp[i][j]=0
                          
          return maxSoFar
      
      
      猜你喜欢
      • 2020-03-22
      • 1970-01-01
      • 2021-12-26
      • 1970-01-01
      • 1970-01-01
      • 2020-12-25
      • 2023-01-19
      • 2017-06-20
      • 2016-11-17
      相关资源
      最近更新 更多