java - 子集和负值

标签 java algorithm subset-sum

我想知道如何使用负值和负目标,现在只要为这些变量提供负值,我的程序就会给出索引越界错误。我需要我的 hasSum 函数在这个项目中使用负值,我不能假设为正。

import java.util.Stack;
import java.util.Scanner;

public class subsetSum {
    static Scanner input = new Scanner(System.in);
    static {
        System.out.print("Enter the target  (T)" + "\n");
    }

    /** Set a value for target sum */
    static int TARGET_SUM = input.nextInt(); //this is the target 

    /** Store the sum of current elements stored in stack */
    static int sumInStack = 0;

    Stack<Integer> stack = new Stack<Integer>();

    public static void main(String[] args) {

        //the size is S
        System.out.println("\n" + "Enter the size of the set (S)");
        int values = input.nextInt(); //size = "values"

        //value of each size entry
        System.out.println("\n" + "Enter the value of each entry for S");

        int [] numbers = new int[values];

        for(int i = 0; i < values; i++) //for reading array
        {
            numbers[i] = input.nextInt();                 
        }

        if(hasSum(numbers, TARGET_SUM)){
            System.out.println("\n" + "Can: ");
            subsetSum get = new subsetSum(); // encapsulation
            get.populateSubset(numbers, 0, numbers.length); 
        }else{
            System.out.println("\n" + "Cannot");
        }
    }

    //method based on dynamic programming O(sum*length)
    public static boolean hasSum(int [] array, int sum)
    {
        int i;
        int len = array.length;
        boolean[][] table = new boolean[sum + 1][len + 1]; //this has to be changed for negative

        //If sum is zero; empty subset always has a sum 0; hence true
        for(i = 0; i <= len; i++){
            table[0][i] = true;
        }

        //If set is empty; no way to find the subset with non zero sum; hence false
        for(i = 1; i <= sum; i++){
            table[i][0] = false;
        }

        //calculate the table entries in terms of previous values
        for(i = 1; i <= sum; i++)
        {
            for(int j = 1; j <= len; j++)
            {
                table[i][j] = table[i][j - 1]; 
                if(!table[i][j] && i >= array[j - 1]){
                    table[i][j] = table[i - array[j - 1]][j - 1];
                }
            }
        }     
        return table[sum][len]; //this has to be changed for negative
    }

    public void populateSubset(int[] data, int fromIndex, int endIndex) {
        /*
         * Check if sum of elements stored in Stack is equal to the expected
         * target sum.
         * 
         * If so, call print method to print the candidate satisfied result.
         */
        if (sumInStack >= TARGET_SUM) {
            if (sumInStack == TARGET_SUM) {
                print(stack);
            }
            // there is no need to continue when we have an answer
            // because nothing we add from here on in will make it
            // add to anything less than what we have...
            return;
        }

        for (int currentIndex = fromIndex; currentIndex < endIndex; currentIndex++) {
            if (sumInStack + data[currentIndex] <= TARGET_SUM) {
                stack.push(data[currentIndex]);
                sumInStack += data[currentIndex];
                /*
                 * Make the currentIndex +1, and then use recursion to proceed
                 * further.
                 */
                populateSubset(data, currentIndex + 1, endIndex);
                sumInStack -= (Integer) stack.pop();
            }
        }
    }

    /**
     * Print satisfied result. i.e. 5 = 1, 4
     */
    private void print(Stack<Integer> stack) {
        StringBuilder sb = new StringBuilder();
        for (Integer i : stack) {
            sb.append(i).append(",");
        }
        // .deleteCharAt(sb.length() - 1)
        System.out.println(sb.deleteCharAt(sb.length() - 1).toString());
    }
}

最佳答案

您是要求子集的总和还是子数组
如果是子集,那么简单的递归就可以解决问题,例如:

public static boolean hasSum(int [] array, int sum)
{
    return hasSum(array, 0, 0, sum);
}

private static boolean hasSum(int[] array, int index, int currentSum, int targetSum) {
    if (currentSum == targetSum)
        return true;
    if (index == array.length)
        return false;
    return hasSum(array, index + 1, currentSum + array[index], targetSum) || // this recursion branch includes current element
           hasSum(array, index + 1, currentSum, targetSum); // this doesn't
}

如果您要查找子数组,我会使用prefix sums ,例如:

public static boolean hasSum(int [] array, int sum)
{
    int[] prefixSums = new int[array.length];
    for (int i = 0; i < prefixSums.length; i++) {
        prefixSums[i] = (i == 0) ? array[i] : array[i] + prefixSums[i - 1];
    }

    for (int to = 0; to < prefixSums.length; to++) {
        if (prefixSums[to] == sum)
            return true; // interval [0 .. to]
        for (int from = 0; from < to; from++) {
            if (prefixSums[to] - prefixSums[from] == sum)
                return true; // interval (from .. to]
        }
    }
    return false;
}

顺便说一句,我认为从静态初始化程序中的 Scanner 读取输入值是个坏主意,为什么不将它们移至 main()

关于java - 子集和负值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36904520/

相关文章:

Python 子集和

c++ - 这个子集和问题的解决方案是如何工作的?

java - java中的哈希码桶分布

java - MetaController 应该观察三个对象

Javafx 2D 迷宫标准解决方案不起作用

algorithm - 计算和应用摩擦力

java - 检查 Selenium Hub/Node 是否在给定端口上运行

java - 我正在尝试在 java 中将日期转换为字符串。但我需要在 javascript 中为调用日期编码

algorithm - 计算对象树中的最大重复子树

arrays - 检查特殊数组方程的子集和