Javascript 尝试在不使用其他算法的情况下使用递归求解

Javascript 尝试在不使用其他算法的情况下使用递归求解,javascript,algorithm,recursion,Javascript,Algorithm,Recursion,我试图更好地理解递归,以便更好地实现动态编程原理。我知道这个问题可以用Kadane的算法解决;但是,我想使用递归来解决它 问题陈述: 给定一个整数数组,找到具有最大和的非相邻元素的子集。计算该子集的和 我编写了以下部分解决方案: const maxSubsetSum = (arr) => { let max = -Infinity const helper = (arr, len) => { if (len < 0) return max

我试图更好地理解递归,以便更好地实现动态编程原理。我知道这个问题可以用Kadane的算法解决;但是,我想使用递归来解决它

问题陈述:

给定一个整数数组,找到具有最大和的非相邻元素的子集。计算该子集的和

我编写了以下部分解决方案:

const maxSubsetSum = (arr) => {
    let max = -Infinity

    const helper = (arr, len) => {
        if (len < 0) return max
        let pointer = len
        let sum = 0
        while (pointer >= 0) {
            sum += arr[pointer]
            pointer -= 2
        }
        return max = Math.max(sum, helper(arr, len - 1))
    }
    return helper(arr, arr.length - 1)
}

我的算法计算13。我知道这是因为当我开始我的算法时,我的(n-2)值是计算出来的,但我没有考虑其他(n-3)或更多的子集,它们仍然验证问题陈述的条件。我无法理解解释其他值的逻辑,请指导我如何实现。

代码将递归(调用
helper
inside
helper
)与迭代(调用
while
循环inside
helper
)相结合。您应该只使用递归

对于数组的每个元素,有两种选择:

  • 跳过当前元素。在这种情况下,总和不变,可以使用下一个元素。因此递归调用是
    sum1=helper(arr,len-1,sum)
  • 使用当前元素。在这种情况下,当前元素被添加到总和中,必须跳过下一个元素。因此递归调用是
    sum2=helper(arr,len-2,sum+arr[len])
  • 所以代码看起来像这样:

    const maxSubsetSum = (arr) => {
    
        const helper = (arr, len, sum) => {
            if (len < 0) return sum
            let sum1 = helper(arr, len - 1, sum)
            let sum2 = helper(arr, len - 2, sum + arr[len])
            return Math.max(sum1, sum2)
        }
    
        return helper(arr, arr.length - 1, 0)
    }
    
    const maxSubsetSum=(arr)=>{
    常量助手=(arr、len、sum)=>{
    如果(len<0)返回和
    设sum1=helper(arr,len-1,sum)
    设sum2=helper(arr,len-2,sum+arr[len])
    返回Math.max(sum1,sum2)
    }
    返回帮助器(arr,arr.length-1,0)
    }
    
    您的想法是正确的,一旦您从当前索引开始,就需要从(n-2)递归。但您似乎不明白,您不需要运行数组来获得和,然后递归。 所以正确的方法是

    • 包括当前项并在剩余的n-2项上递归,或

    • 不包括当前项并在剩余的n-1项上递归

    让我们看看这两种选择:

    选择1:

    您选择在当前索引中包含该项。然后对剩余的n-2项进行递归。因此,您的最大值可以是项目本身,而无需添加到剩余的任何n-2项目或从n-2项目添加到某些项目。 因此,Math.max(arr[idx],arr[idx]+recurse(idx-2))是这个选择的最大值。如果递归(IDX-2)给你无穷大,你只需考虑当前索引中的项。< /P> 选择2:

    您没有选择在当前索引中包含该项。所以只需对剩余的n-1项进行递归-递归(n-1)

    最后的最大值是这两个选项中的最大值

    代码是:

    const maxSubsetSum = (arr) => {
        let min = -Infinity
        const helper = (arr, idx) => {
          if ( idx < 0 ) return min
          let inc = helper(arr, idx-2)
          let notInc = helper(arr, idx-1)
          inc = inc == min ? arr[idx] : Math.max(arr[idx], arr[idx] + inc)
          return Math.max( inc, notInc )
        }
        return helper(arr, arr.length - 1)
    }
    
    console.log(maxSubsetSum([-3, -5, -7, -8, 10]))
    console.log(maxSubsetSum([-3, -5, -7, -8, -10]))
    console.log(maxSubsetSum([-3, 5, 7, -8, 10]))
    console.log(maxSubsetSum([3, 5, 7, 8, 10]))
    
    • 对于所有项目均为负值的情况:
    在这种情况下,您可以说没有可以组合在一起以获得最大总和的项目。如果这是要求,则结果应为零。在这种情况下,只需将0作为默认结果返回0即可。在这种情况下,代码是:

    const maxSubsetSum = (arr) => {
        const helper = (arr, idx) => {
          if ( idx < 0 ) return 0
          let inc = arr[idx] + helper(arr, idx-2)
          let notInc = helper(arr, idx-1)
          return Math.max( inc, notInc )
        }
        return helper(arr, arr.length - 1)
    }
    
    const maxSubsetSum=(arr)=>{
    const helper=(arr,idx)=>{
    如果(idx<0)返回0
    let inc=arr[idx]+助手(arr,idx-2)
    let notInc=helper(arr,idx-1)
    return Math.max(inc,notInc)
    }
    返回帮助器(arr,arr.length-1)
    }
    
    • 随附备忘录:
    您可以为递归期间访问的索引记忆此解决方案。只有一种状态,即索引,因此您的备忘录是一维的。带备注的代码为:

    const maxSubsetSum = (arr) => {
        let min = -Infinity
        let memo = new Array(arr.length).fill(min)
        const helper = (arr, idx) => {
          if ( idx < 0 ) return min
          if ( memo[idx] !== min) return memo[idx]
          let inc = helper(arr, idx-2)
          let notInc = helper(arr, idx-1)
          inc = inc == min ? arr[idx] : Math.max(arr[idx], arr[idx] + inc)
          memo[idx] = Math.max( inc, notInc )
          return memo[idx]
        }
        return helper(arr, arr.length - 1)
    }
    
    const maxSubsetSum=(arr)=>{
    设min=-无穷大
    let memo=新数组(arr.length).fill(min)
    const helper=(arr,idx)=>{
    如果(idx<0)返回最小值
    如果(备忘录[idx]!==min)返回备忘录[idx]
    let inc=helper(arr,idx-2)
    let notInc=helper(arr,idx-1)
    inc=inc==min?arr[idx]:数学最大值(arr[idx],arr[idx]+inc)
    备注[idx]=Math.max(inc,notInc)
    返回备忘录[idx]
    }
    返回帮助器(arr,arr.length-1)
    }
    
    基本版本非常简单,具有明显的递归。我们要么在总和中包含当前值,要么不包含当前值。如果我们这样做,我们需要跳过下一个值,然后在剩余的值上重复。如果没有,则需要在当前值之后的所有值上重复出现。我们选择这两个结果中较大的一个。这几乎直接转化为代码:

        const maxSubsetSum = ([n, ...ns]) => 
          n == undefined  // empty array
            ? 0
            : Math .max (n + maxSubsetSum (ns .slice (1)), maxSubsetSum (ns))
    

    此代码已被接受:

    函数maxSubsetSum(A){
    返回A.reduce((ux,i)=>
    A[i]=Math.max(A[i],A[i-1]|0,A[i]+(A[i-2]|0));
    }
    
    但是,如果尝试递归那么远,(我尝试提交Scott Sauyet的),我相信会导致运行时错误,因为我们可能会超过递归限制

    为了好玩,这里有一个自下而上的自上而下的方法:)

    函数f(A,i=0){
    如果(i>A.length-3)
    返回A[i]=Math.max(A[i]| 0,A[i+1]|0);
    //填表
    f(A,i+1);
    返回A[i]=Math.max(A[i],A[i]+A[i+2],A[i+1]);
    }
    变量As=[
    [3, 7, 4, 6, 5], // 13
    [2, 1, 5, 8, 4], // 11
    [3, 5, -7, 8, 10] // 15
    ];
    例如{
    控制台日志(“”+A);
    控制台日志(f(A));
    
    }
    这很有帮助,您将如何记忆此解决方案?它是2D数组还是1D数组?@Altaf我认为它是1D数组,因为唯一需要记忆的是给定
    len
    的部分和。我在记忆解决方案时遇到困难,所以我所做的是在helper
    const newArr=new array(arr.length)之前声明一个数组。fill(-1)
    编写了一个条件以返回
    if(newArr[len]!==-1)返回newArr[len]
    然后将helper函数的返回值更改为
    返回newArr[len]=Math.max(sum1,sum2)
    ,但是我没有做正确的事情。这为输入
    [-3]提供了0
    
    const maxSubsetSum = (arr) => {
        let min = -Infinity
        let memo = new Array(arr.length).fill(min)
        const helper = (arr, idx) => {
          if ( idx < 0 ) return min
          if ( memo[idx] !== min) return memo[idx]
          let inc = helper(arr, idx-2)
          let notInc = helper(arr, idx-1)
          inc = inc == min ? arr[idx] : Math.max(arr[idx], arr[idx] + inc)
          memo[idx] = Math.max( inc, notInc )
          return memo[idx]
        }
        return helper(arr, arr.length - 1)
    }
    
        const maxSubsetSum = ([n, ...ns]) => 
          n == undefined  // empty array
            ? 0
            : Math .max (n + maxSubsetSum (ns .slice (1)), maxSubsetSum (ns))