Клонирование списка массивов в другой список массивов не работает в DP

#java #arraylist #dynamic-programming

Вопрос:

Вот код Java для поиска кратчайшего объединения элементов массива wordBank для построения строки Terget с использованием динамического программирования.

Пример:

Ввод: Банк слов = {«ab», «c», «d», «abc», «ad»}, Цель = «abcd».

Вывод: {«abc», «d»}.

Для этого я сохранил комбинацию элементов в виде списка массивов в хэш-карте. Однако хэш-карта не хранит значения правильно, т. Е. Значения меняются, когда я рекурсивно вызываю функцию, хотя я клонировал список массивов перед добавлением его на карту.

Есть идеи, почему это происходит?

Код хорошо работает с массивами.

 static ArrayList<String> bestConstruct(String target, String[] wordBank, HashMap<String, ArrayList<String>> map) {
    
    if(target.isEmpty())
    {
        return new ArrayList<String>();
    }
    
    if(map.containsKey(target))
        return map.get(target);
    
    ArrayList<String> shortestCombination = null;
    for (String word : wordBank) {
        
        if(target.startsWith(word)) {
            String newTarget = target.substring(word.length(), target.length());
            
            ArrayList<String> combination = bestConstruct(newTarget, wordBank, map);
            
            
            if(combination != null) {
                combination.add(word);
                
                if(shortestCombination == null || combination.size() < shortestCombination.size())
                    shortestCombination = (ArrayList<String>)(combination.clone());
            }
        }
    }
    map.put(target,  (ArrayList<String>) (shortestCombination.clone()));
    return shortestCombination;
}
 

Комментарии:

1. Нет необходимости использовать clone() для arraylist. Используйте конструктор копирования: new ArrayList<>(combination) .

2. Я сделал то же самое, но все равно это не работает

3. «значения меняются, когда я рекурсивно вызываю функцию» можете ли вы показать пример?

Ответ №1:

Проблема заключается во взаимодействии между этими линиями:

     if(map.containsKey(target))
        return map.get(target);
 

и

             ArrayList<String> combination = bestConstruct(newTarget, wordBank, map);
            
            
            if(combination != null) {
                combination.add(word);
 

Если вы возвращаете список с памятью, вы обновляете его, прежде чем клонировать.

В общем, не полагайтесь на то, что звонящие «поступят правильно»: если вы не хотите, чтобы список на карте обновлялся, сделайте копию самостоятельно, прежде чем возвращать его:

     if(map.containsKey(target))
        return new ArrayList<>(map.get(target));
 

Возможно, вам также потребуется обработать случай, когда строка не может быть создана из банка слов.

Комментарии:

1. что вы имели в виду, говоря «не полагайтесь на то, что звонящие будут поступать правильно»? Вы имеете в виду, потому что они передают ссылки?

2. @Elahe Я имею в виду, что если вы хотите убедиться, что вызывающий абонент не вносит изменений в списки, хранящиеся на карте, не давайте им список, хранящийся на карте. Устраните их выбор поступить неправильно.