当前位置: 首页 > 知识库问答 >
问题:

为什么记忆代码失败,而递归方法适用于具有正积的子数组的最大长度?

谷梁向荣
2023-03-14

我正在努力解决这个问题:

给定一个整数nums数组,求其所有元素的乘积为正的子数组的最大长度。

数组的子数组是从该数组中取出的零个或多个值的连续序列。

返回具有正积的子阵列的最大长度。

示例1:

Input: nums = [1,-2,-3,4]
Output: 4
Explanation: The array nums already has a positive product of 24.

示例2:

Input: nums = [0,1,-2,-3,-4]
Output: 3
Explanation: The longest subarray with positive product is [1,-2,-3] which has a product of 6.
Notice that we cannot include 0 in the subarray since that'll make the product 0 which is not positive.

示例3:

Input: nums = [-1,-2,-3,0,1]
Output: 2
Explanation: The longest subarray with positive product is [-1,-2] or [-2,-3].

我的解决方案:

class Solution {
    public int getMaxLen(int[] nums) {
        int n = nums.length;
        Map<String,Integer> map = new HashMap<>();
        int v1 = helper(nums,n,1,0,map);
        if(v1 == -1)
            return 0;
        
        return v1;
    }
    
    public int helper(int[] nums,int n,long product,int length,Map<String,Integer> map) {
        if(n == 0){
            if(product>0)
                return length;
            
            return -1;
        }
        
        String str = "" + n + "-" + product+"-"+length;
        
        if(map.get(str) != null){
            if(product > 0)
                return map.get(str);
        }
        
        if(nums[n-1] == 0){
            int v1 = helper(nums,n-1,1,0,map);
            
            if(product <= 0)
                length = 0;
            
            int v2 = Math.max(length,v1);
            
            map.put(str,v2);
            return v2;            
        }
        else{
            int v4 = helper(nums,n-1,product*nums[n-1],length+1,map);
            int v3 = helper(nums,n-1,nums[n-1],1,map);
        
            if(product <= 0)
                length = 0;
            
            int v5 = Math.max(length,Math.max(v3,v4));
           
            map.put(str,v5);
            return v5;
        }
    }
}

失败时间:

Input: 
[70,-18,75,-72,-69,-84,64,-65,0,-82,62,54,-63,-85,53,-60,-59,29,32,59,-54,-29,-45,0,-10,22,42,-37,-16,0,-7,-76,-34,37,-10,2,-59,-24,85,45,-81,56,86]
Output: 13
Expected: 14

我在寻找解决方案,但每个人都在直接制表,而不是记忆

共有1个答案

明正德
2023-03-14

首先,你的问题不在于你的记忆,你可以简单地把与记忆相关的部分注释掉,你仍然会得到错误的答案。您的问题是堆栈溢出,简单地将数字相乘[-82,62,54,-63,-85,53,-60,-59,29,32,59,-54,-29,-45]超过了最大长值,您将得到错误的答案,因为您将这些数字的乘法存储在长值中。为了解决这个问题,我消除了数字的大小,只使用它们的符号。我还使用可以在我的代码中看到的函数splitToZero将数组拆分为包含非零值的较小数组。

但你的回忆录也不正确。我已经为helper实现了两种方法,展示了Memotation的改进,您可以看到,如果使用Memotation,与不使用Memotation时相比,速度会快20倍左右(我刚刚调用了1000次这些方法,以便有一个合理的时间进行比较)。

public int getMaxLen(int[] nums) {
    List<int[]> ints = splitToZero(nums);
    timeComparison(ints);
    int max = 0;
    for (int[] arr : ints) {
        Map<int[], Integer> map = new HashMap<>();
        int len = arr.length;
        int v1 = helperWithMemotazation(arr, len, 1, 0, map);
        if (v1 > max)
            max = v1;
    }
    return max;
}

private void timeComparison(List<int[]> ints) {
    long startTimeMillis = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++)
        for (int[] arr : ints) {
            Map<int[], Integer> map = new HashMap<>();
            int len = arr.length;
            helperWithMemotazation(arr, len, 1, 0, map);
        }
    long endTimeMillis = System.currentTimeMillis();
    System.out.println(endTimeMillis - startTimeMillis);

    startTimeMillis = System.currentTimeMillis();
    for (int i = 0; i < 1000; i++)
        for (int[] arr : ints) {
            int len = arr.length;
            helperWithoutMemotazation(arr, len, 1, 0);
        }
    endTimeMillis = System.currentTimeMillis();
    System.out.println(endTimeMillis - startTimeMillis);
}

public List<int[]> splitToZero(int[] nums) {
    List<int[]> result = new ArrayList<>();
    List<Integer> list = new ArrayList<>();
    for (int num : nums) {
        if (num != 0) {
            list.add(num);
        } else {
            if (list.size() > 0) {
                int[] temp = new int[list.size()];
                for (int j = 0; j < list.size(); j++)
                    temp[j] = list.get(j) / Math.abs(list.get(j));
                result.add(temp);
                list.clear();
            }
        }
    }
    if (list.size() > 0) {
        int[] temp = new int[list.size()];
        for (int j = 0; j < list.size(); j++)
            temp[j] = list.get(j) / Math.abs(list.get(j));
        result.add(temp);
    }
    return result;
}

public int helperWithMemotazation(int[] nums, int n, long product, int length, Map<int[], Integer> map) {
    if (n == 0) {
        if (product > 0)
            return length;
        return -1;
    }
    if (map.containsKey(nums)) {
        return map.get(nums);
    }
    int v4 = helperWithMemotazation(nums, n - 1, product * nums[n - 1], length + 1, map);
    int v3 = helperWithMemotazation(nums, n - 1, nums[n - 1], 1, map);
    if (product <= 0)
        length = 0;
    int v5 = Math.max(length, Math.max(v3, v4));
    map.put(nums, v5);
    return v5;
}

public int helperWithoutMemotazation(int[] nums, int n, long product, int length) {
    if (n == 0) {
        if (product > 0)
            return length;
        return -1;
    }
    int v4 = helperWithoutMemotazation(nums, n - 1, product * nums[n - 1], length + 1);
    int v3 = helperWithoutMemotazation(nums, n - 1, nums[n - 1], 1);
    if (product <= 0)
        length = 0;
    return Math.max(length, Math.max(v3, v4));
}
 类似资料:
  • 问题内容: Python具有最大的递归深度,但没有最大的迭代深度。为什么限制递归?像迭代一样对待递归而不限制递归调用的数量会更自然吗? 让我只说这个问题的根源在于尝试实现流。例如,假设我们要编写一个流以产生自然数: 流的递归定义非常吸引人。但是,我想更好/更多的pythonic方法是使用生成器。 问题答案: 实际上这里有一些问题。 首先,正如NPE的回答很好地说明的那样,Python不会消除尾部调

  • 问题:找到具有重复元素的传染性子数组的最大长度。 例如: -答案是3,因为2重复3次是最大重复次数。 -答案是1 -答案是2 但是递归函数应该只有list作为参数

  • 本文向大家介绍LCM的最大长度子数组等于C ++中的乘积,包括了LCM的最大长度子数组等于C ++中的乘积的使用技巧和注意事项,需要的朋友参考一下 假设我们有一个数组A。我们必须找到子数组的最大长度,它的LCM与该子数组元素的乘积相同。如果找不到这种子数组,则返回-1。假设数组为{6,10,21},则长度为2,因为在那里有子数组{10,21},其LCM为210,乘积也为210。 该方法是直接的。我

  • 给定一个只有和的数组,求取和数目相等的最大子数组的长度。例如,给定一个数组 编写递归函数。这个函数接受3个输入:一个数组-A,它的第一个元素的索引-start,最后一个元素的索引-end,并返回largestsubarray的大小。如果没有找到数量相等的子数组,则函数应返回0。 如何修复此代码?请帮忙。谢了。

  • Q、 给定整数数组nums,返回最长严格递增子序列的长度。 子序列是一个序列,可以通过删除一些元素或不删除任何元素而从数组中派生,而不改变其余元素的顺序。例如,[3,6,2,7]是数组[0,3,1,6,2,2,7]的子序列。 示例1: 输入:nums=[10,9,2,5,3,7,101,18] 输出:4 说明:最长的递增子序列为[2,3,7101],因此长度为4。 答案: 我的递归代码工作正常,但

  • 我正在尝试使用javascript中的minimax算法实现一个连接四个AI。目前,速度很慢。除了我将要实现的alpha-beta修剪之外,我想知道是否值得将游戏状态散列为 他们的启发式评估 下一个最佳举措 我可以立即明白为什么2会很有用,因为有很多方法可以达到相同的游戏状态,但我想知道我是否也必须散列当前深度才能使其工作。例如,如果我以3的深度达到这种状态(所以只说再向前看4步),而深度为2,向