【问题标题】:Memoize a void recursive function记忆一个无效的递归函数
【发布时间】:2021-10-23 12:33:53
【问题描述】:

我有一个递归函数。我需要记住它,但找不到方法。 请告诉我路。

代码如下:

int ans = Integer.MAX_VALUE;

void solve(int[] arr, int idx, int sum) {
        if(idx == arr.length) {
            if(sum >= 0)
            ans = Math.min(ans, sum);
            //t[idx] = Math.min(t[idx], su);
            //System.out.println("ans = " + ans);
            return;
        }
        
        //if(t[idx] != 0) return t[idx];
        
        int sum1 = sum, sum2 = sum;
        
        sum1 += arr[idx];
        sum2 += -arr[idx];
        
        solve(arr, idx + 1, sum1);
        
        solve(arr, idx + 1, sum2);
        
        //return t[idx];
    }

提前感谢 DP 中的菜鸟。

【问题讨论】:

    标签: recursion dynamic-programming memoization


    【解决方案1】:

    所有(递归)调用似乎不同,是吗?那么记忆将无济于事。

    但不,对于相同的idxsum1sum2 可能相等,而 arr[idx] == 0

        solve(arr, idx + 1, sum1);
        if (sum2 != sum1) {
            solve(arr, idx + 1, sum2);
        }
    

    更整洁的是:

        int value = arr[idx];
        ++idx;
        solve(arr, idx, sum + value);
        if (value != 0) {
            solve(arr, idx, sum - value;
        }
    

    由于每个递归调用通常会使进一步的调用加倍,这可以将 2n 大幅减少到 n(当全为零时)。

    这里的记忆意味着,如果 sum2 == sum1 那么ans 是记忆的值。

    这确实不是人们通常在记忆下所理解的。

    伪代码中可能是:

    Map<int[], Integer> memoization = new HashMap<>();
    void solve(int[] arr, int idx, int sum) {
        if (idx == 0) {
            Integer a = memoization.get(arr);
            if (a != null) {
                ans = a;
                return;
            }
        }
        if (idx == arr.length) {
            memoization.put(arr, Arrays.copy(ans));
        }
        ...
    }
    

    这并没有充分发挥记忆作用,可能会记忆子数组 arr[0 .. i]。这可能是所需的解决方案。

    之所以不使用通常的函数——返回一些记忆值——而是使用一个丑陋的全局变量,是因为它是累积的。在纯函数样式中,它需要同时是参数ansTillNow 和结果。

    这把繁重的工作留给了你。另请注意,该解决方案实际上在数学上非常简单。

    【讨论】:

    • 我认为我的回答太刻薄了,所以一个提示:memoized 可能不是输入数组,而只是映射到 ans 的 idx 的总和。然后 if 不需要,因为 memoization 处理它。 (这里的答案应该解释,而不是做别人的功课。)
    猜你喜欢
    • 2012-11-26
    • 1970-01-01
    • 2014-10-31
    • 2012-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-28
    • 1970-01-01
    相关资源
    最近更新 更多