Найти два подмножества с одинаковой суммой в массиве - PullRequest
0 голосов
/ 16 декабря 2018

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

Например, наш ввод может быть [3,1,2,4].Мое ожидаемое решение этой проблемы - [[3,2],[1,4]] или [[2,3],[4,1]] (Либо было бы приемлемо. Но дублированный ответ не был принят, например [[3,2],[1,4],[2,3],[4,1]]), потому что 1 + 4 = 2 + 3. И если мой ввод не может привести к такомуВ комбинации мой код может просто вывести Null или [[]].

Я попытался решить эту проблему с помощью DFS (Поиск в глубину вначале), и мой текущий код выглядит следующим образом:

public static List<List<Integer>> twoPartSum(int[] arr){

    // corner case

    List<List<Integer>> ret = new ArrayList<>();
    List<Integer> part = new ArrayList<>();

    if(arr == null || arr.length <= 1){
        ret.add(part);
        return ret;
    }

    // usual case

    int sum = 0;
    for(int i : arr){
        sum += i;
    }

    helper(arr, 0, sum/2, 0, ret, part);

    return ret;

}

private static void helper(int[] arr, int curSum ,int target, int index, List<List<Integer>> ret, List<Integer> part){

    //base case
    if(curSum == target){

        ret.add(new ArrayList<>(part));
        return;
    }

    // such a pair does not exits
    if(curSum > target ){
        return;
    }


    for(int i = index; i < arr.length; i++){

        swap(arr, i, index);
        curSum += arr[index];
        part.add(arr[index]);

        helper(arr, curSum, target, index + 1, ret, part);

        curSum -= arr[index];
        part.remove(index);
        swap(arr, i, index);

    }


}

private static void swap(int[] arr, int i, int j){

    int temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;

}

Мой текущий результат [[3,2],[1,4],[2,3],[4,1]] со входом [3,1,2,4] К сожалению, я не могу понять, как дедуплицировать мой результат.Кто-нибудь может предложить какую-то идею?Заранее спасибо!

На входе могут быть повторяющиеся числа, например [3,1,1,1,2,4].И, видимо, мое текущее решение не может охватить эту ситуацию.Я буду признателен, если вы сможете предложить такой общий алгоритм.Но если это будет слишком сложно, я буду рад узнать решение для отдельного массива.

Ответы [ 2 ]

0 голосов
/ 16 декабря 2018

Я наконец-то нашел лучший способ решить эту проблему.И я хотел бы поделиться с людьми, которые заинтересованы в этом вопросе.Код также может работать с дублирующимися элементами во входном массиве.

Я изменил логику этой проблемы.Дерево рекурсии для этого кода показано следующим образом.По сути, это двоичное дерево, и каждая ветвь обозначает, добавлять ли элемент в массив или нет.Индекс массива - это глубина этого дерева.

                       /            \
  arr[0] = 3          3(add 3)       0(don't add 3)     depth(index of the arr) == 0  
                   /      \       /      \
  arr[1] = 1    1+3      0+3     1+0      0+0           depth == 1
               /  \     /   \   /   \    /   \
  arr[2] = 2 2+4  0+4  2+3 0+3 2+1  0+1 2+0  0+0        depth == 2
             /\   /\   /\  /\   /\   /\  /\   /\ 
            ......

Дерево, представленное выше, является полным решением для сумм всех подмножеств массива.И, конечно же, мы можем остановить любую ветвь, указав критерий остановки для этой конкретной проблемы:

// base case 1: found the answer
if(curSum == target){
    ret.add(new ArrayList<>(part));
    return;
}

Действительный код моей проблемы показан следующим образом:

public static List<List<Integer>> twoPartSum2(int[] arr){

    // corner case

    List<List<Integer>> ret = new ArrayList<>();
    List<Integer> part = new ArrayList<>();

    if(arr == null || arr.length <= 1){
        ret.add(part);
        return ret;
    }

    // usual case

    Arrays.sort(arr); // make sure the same numbers will be lined together

    int sum = 0;
    for(int i : arr){
        sum += i;
    }

    helper2(arr, 0, sum/2, 0, ret, part);

    return ret;

}

private static void helper2(int[] arr, int curSum ,int target, int index, List<List<Integer>> ret, List<Integer> part){

    // base case 1: found the answer
    if(curSum == target){
        ret.add(new ArrayList<>(part));
        return;
    }

    // base case 2: solution not found
    if(index == arr.length || curSum > target){
        return;
    }

    // recursion case 1: adding current element in the candidate list ("part")
    part.add(arr[index]);
    helper2(arr, curSum + arr[index], target,index + 1,ret, part);
    part.remove(part.size()-1);

    // deduplicate the same elements
    while(index + 1 < arr.length && arr[index] == arr[index+1]){
        index++;
    }

    // recursion case 2: not adding current element in the candidate list ("part")
    helper2(arr, curSum, target, index + 1,ret,part);

}

Обратите внимание, что для дедупликации нашего решения мы должны пропустить одни и те же элементы в нашем массиве, именно поэтому массив сортируется в самом начале Arrays.sort(arr); А затем у нас есть ниже, чтобы пропустить одинаковые элементы в каждомlayer.

// deduplicate the same elements
while(index + 1 < arr.length && arr[index] == arr[index+1]){
    index++;
}

Например, если наш массив [1,1,1,3].Тогда у нас будет дерево рекурсии, показанное следующим образом:

                           /             \
  arr[0] = 1              1               0
                     /        \           |    (the other two '1's are skipped)
  arr[1] = 1       1+1        0+1         |     
                  /   \        |          |     (the other one '1' is skipped)   
  arr[2] = 1    1+2   0+2      |          | 
               / \    / \     / \        / \
  arr[3] = 3 3+3 0+3 3+2 0+2 3+1 0+1   3+0 0+0

Ответ: 6, 3 , 5, 2, 4, 1, 3 , 0

Некоторые из вас могут спросить, почему у нас два 3?Ну, на самом деле, они отличаются 3 в этой задаче, так как первый 3 получается 1 + 1 + 1, а второй из 3, последний элемент в массиве [1,1,1,3].В результате они по-прежнему являются различными решениями этой проблемы.

Логика, которую я использовал ранее в этом вопросе, все еще может работать, но я предпочитаю не публиковать ее в данный момент, поскольку она более запутанная.Однако, если кто-то все еще интересуется этой проблемой, пожалуйста, оставьте комментарий, и я обновлю его, когда я буду свободен.Спасибо!

0 голосов
/ 16 декабря 2018

Для устранения дублирования вашего результата вы можете разместить порядок в вашем подмножестве, сказав, что элементы в каждом подмножестве должны быть в возрастающем порядке (или уменьшаться, если вы предпочитаете это).Это означает, что [3,2] будет переписано в [2,3], и вы получите [2,3],[2,3],[1,4],[1,4] в вашем примере.Если вы храните свои подмножества в Set вместо ArrayList, дубликаты не будут добавлены в первую очередь, и у вас будет [2,3], [1,4].

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...