这段动态编程代码有什么问题?

what is wrong in this code for dynamic programming?

你好这是我第一次在这个社区发帖

所以,我需要做的是:

编写一个函数 canSum(),将目标总和和数字数组作为参数。

该函数应该 return 一个布尔值,指示是否可以使用数组中的数字生成目标总和。

您可以根据需要多次使用数组的元素

您可以假设所有输入数字都是非负数。

import java.util.HashMap;
import java.util.Map;

public class Main {
    public static void main(String[] args) {
        System.out.println(canSum(7, new int[]{2, 3}));         //true
        System.out.println(canSum(7, new int[]{5, 3, 4, 7}));   //true
        System.out.println(canSum(7, new int[]{2, 4}));         //false
        System.out.println(canSum(8, new int[]{2, 3, 5}));      //true
        System.out.println(canSum(300, new int[]{7, 14}));      //false

    }
    private static Map<Integer, Boolean> memo = new HashMap<>();

    public static boolean canSum(int target, int[] arr){

        if(memo.containsKey(target)) return memo.get(target);
        if(target == 0) return true;
        if(target < 0) return false;

        for(int i = 0; i< arr.length;i++){
            int remainder = target - arr[i];
            if(canSum(remainder,arr)){
                memo.put(target, true);
                return true;
            }
        }
        memo.put(target,false);
        return false;
    }

程序输出: 真的 真的 真的 真的 真

什么时候应该: 真的 真的 错误的 真的 假

您的问题是您从不在方法调用之间清除 Map<Integer, Boolean> memo。如果可以使用 true 或 false 生成总和,则保存的映射仅对一种方法有效 运行,因此您的代码不应在不同调用之间重复使用相同的映射。

一个简单的解决方法是在每次调用后手动清除地图:

System.out.println(canSum(7, new int[] { 2, 3 })); //true
memo.clear();
System.out.println(canSum(7, new int[] { 5, 3, 4, 7 })); //true
memo.clear();
System.out.println(canSum(7, new int[] { 2, 4 })); //false
memo.clear();
System.out.println(canSum(8, new int[] { 2, 3, 5 })); //true
memo.clear();
System.out.println(canSum(300, new int[] { 7, 14 })); //false
memo.clear();

将创建输出

true
true
false
true
false

一个更优雅的解决方案是不使用字段来存储地图,而是在需要时在内部创建它。您可以使用 2 种方法这样做,例如:

public static boolean canSum(int target, int[] arr) {
    Map<Integer, Boolean> memo = new HashMap<>();
    return canSum(target, arr, memo);
}

private static boolean canSum(int target, int[] arr, Map<Integer, Boolean> memo) {
    if (memo.containsKey(target)) {
        return memo.get(target);
    }
    if (target == 0) {
        return true;
    }
    if (target < 0) {
        return false;
    }

    for (int i = 0; i < arr.length; i++) {
        int remainder = target - arr[i];
        if (canSum(remainder, arr, memo)) {
            memo.put(target, true);
            return true;
        }
    }
    memo.put(target, false);
    return false;
}

它不起作用,因为您的 memo 地图是一个静态成员变量,它也将包含所有以前的迭代。

因此,当您在最后一行中执行 memo.put() 时,它添加了不同的组合,这些组合直接在 memo.containsKey 中重复使用。

您可以在该函数内移动该变量。它应该开始正常工作。

不要把备忘录当作静态的

public class Main {
    public static void main(String[] args) {
        System.out.println(canSum(7, new int[]{2, 3}));         //true
        System.out.println(canSum(7, new int[]{5, 3, 4, 7}));   //true
        System.out.println(canSum(7, new int[]{2, 4}));         //false
        System.out.println(canSum(8, new int[]{2, 3, 5}));      //true
        System.out.println(canSum(300, new int[]{7, 14}));      //false

    }
    /* 
     * private static Map<Integer, Boolean> memo = new HashMap<>(); 
     * 
     * It will check for first one and will store the result, then for rest
     * operation it will rend stored data only
     */

    public static boolean canSum(int target, int[] arr){
        
        Map<Integer, Boolean> memo = new HashMap<>();

        if(memo.containsKey(target)) return memo.get(target);
        if(target == 0) return true;
        if(target < 0) return false;

        for(int i = 0; i< arr.length;i++){
            int remainder = target - arr[i];
            if(canSum(remainder,arr)){
                memo.put(target, true);
                return true;
            }
        }
        memo.put(target,false);
        return false;
    }
}

您应该将备忘录对象作为函数参数并将其默认值设置为None。这样就不会混淆全局作用域和每次调用函数时清除memo对象了。

简单的伪代码:

def canSum(targetSum: int, numbers: list[int], memo=Optional[dict] = None) -> Bool:
    # Memo Checking Logic
    if memo is None:
        memo = {}

    # Base Cases
    # Memo Fetching Logic
    if targetSum in memo:
        return memo[targetSum]

    if targetSum < 0:
        return False

    if targetSum == 0:
        return True

    # Recursive Case
    for num in numbers:
        remainder = targetSum - num
        # Memo Caching Logic
        if canSum(remainder, numbers, memo):
            memo[targetSum] = True
            return True

    memo[targetSum] = False
    return False