Недавно я смотрел учебник по динамическому программированию на Youtube, объясняющий динамическое программирование, но репетитор решил проблемы с JavaScript. Я, с другой стороны, использую Java для структур данных и алгоритмов. При реализации динамического программирования для решения вопроса. Я обнаружил, что получил решение проблемы при использовании int[]
, но получил неправильный ответ при использовании ArrayList<Integer>
, потому что каким-то образом ArrayList, уже сохраненный в HashMap, модифицировался внутри.
Вопрос: Напишите функцию bestSum(targetSum, numbers), которая принимает targetSum и массив чисел в качестве аргументов и возвращает массив, содержащий кратчайшую комбинацию чисел, которая в сумме дает точно заданную сумму. Пример:
bestSum(7,new int[]{2,1,3}) => [3,3,1] //другие возможности, но не ответ:[2,2,2,1], [1,1,1, 1,1,1,1], [2,2,1,1,1] и т. д.
bestSum(100,new int[]{2,5,25}) => [25,25,25,25]
Код с использованием int[]:
public class Persist {
public static HashMap<Integer,int[]> memo = new HashMap<>();
public static int[] bestSum(int n, int[] arr){
if (memo.containsKey(n)){
//System.out.printf("From memo: %d->"+ Arrays.toString(memo.get(n)) +"%n",n);
return memo.get(n);
}
if (n==0)return new int[0];
if (n<0)return null;
int[] minn = null;
for(int i = 0;i<arr.length;i++){
//recursion
var temp = bestSum(n-arr[i],arr);
if (temp!=null){
// ttemp is used to add arr[i] to the initial arr <<temp>>
int[] ttemp = new int[temp.length+1];
System.arraycopy(temp,0,ttemp,0,temp.length);
ttemp[temp.length] = arr[i];
temp = ttemp;
if (minn==null||temp.length<minn.length){
minn = temp;
}
}
}
//System.out.println(n+": "+minn);
memo.put(n,minn);
//System.out.println(memo.get(n));
return minn;
}
public static void main(String[] args){
System.out.println(Arrays.toString(bestSum(7, new int[]{2,1,3})));
}
}
Код с использованием ArrayList<Integer> :
public class Persist {
public static HashMap<Integer,ArrayList<Integer>> memo = new HashMap<>();
public static ArrayList<Integer> bestSum(int n, int[] arr){
if (memo.containsKey(n)){
//System.out.printf("From memo: %d->"+ memo.get(n)+"%n",n);
return memo.get(n);
}
if (n==0)return new ArrayList<>();
if (n<0)return null;
ArrayList<Integer> minn = null;
for(int i = 0;i<arr.length;i++){
var temp = bestSum(n-arr[i],arr);
if (temp!=null){
temp.add(arr[i]);
if (minn==null||temp.size()<minn.size()){
minn = temp;
}
}
}
//System.out.println(n+": "+minn);
memo.put(n,minn);
//System.out.println(memo.get(n));
return minn;
}
public static void main(String[] args){
System.out.println(bestSum(7,new int[]{2,1,3}));
}
}
Единственное различие между двумя фрагментами кода заключается в использовании int[]
и ArrayList<Integer>
соответственно, но один работает, а другой нет. Я хотел бы знать, почему, спасибо.
Ссылка на Youtube объяснение bestSum()
@ Surt Я сделал что-то подобное, но все равно получил неправильные ответы. memo.put(n,minn==null?null:new ArrayList<>(minn));
Легко увлечься мемоизацией и динамическим программированием и забыть о передаче по ссылке и передаче по значению. Ключевое отличие, о котором следует помнить, заключается в том, что ArrayList
передается по ссылке.
Если вы отлаживаете и смотрите на свой hashmap
memo
, вы видите, что размеры int[]
достигают только 3
, тогда как в хэш-карте arraylist большинство значений имеет размер 7
У меня была похожая проблема: кастинг не работает с типом объекта вложенного списка и возвращает пустые списки (List<List<Integer>>)
то же самое относится к С++?
Также hashCode() значения реализации ArrayList одинаков для ключей: 5,6,7
@lordvidex C++ не копируется, если вы не укажете ссылку, хотя копия не распространяется через указатели, если не определены соответствующие конструкторы копирования.
Напомните мне, вы получаете глубокую копию, когда делаете
memo.put(n, minn);
?