【问题标题】:what is wrong in this code for dynamic programming?这段动态编程代码有什么问题?
【发布时间】:2021-07-27 09:36:08
【问题描述】:

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

所以,我需要做的是:

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

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

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

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

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;
    }

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

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

【问题讨论】:

  • 您的第一个方法调用将产生一个带有 {7,true} 的 Map.Entry。在您的第二次和第三次调用中,地图中的此条目将作为结果返回 true。
  • 2 + 3 根本不是 7,甚至没有接近它,为什么它应该返回 true ???!?!?
  • @GiorgosXou 据我了解,数字可以多次使用。所以 2+2+3=7
  • @OHGODSPIDERS 真的,我的错,哈哈,谢谢
  • *我急着回答*

标签: java dynamic-programming


【解决方案1】:

您的问题是您从未在方法调用之间清除您的Map&lt;Integer, Boolean&gt; 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;
}

【讨论】:

  • 在您创建两个方法的部分中,这是一个 OOP 概念吗?
【解决方案2】:

不要把备忘录当成静态的

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;
    }
}

【讨论】:

    【解决方案3】:

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

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

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

    【讨论】:

      【解决方案4】:

      您应该将备忘录对象作为函数参数并将其默认值设置为无。那么每次调用函数时不会混淆全局范围和清除备忘录对象。

      简单的伪代码:

      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
      

      【讨论】:

        猜你喜欢
        • 2015-04-25
        • 2018-09-09
        相关资源
        最近更新 更多