【问题标题】:How to find if any values in array add up to n如何查找数组中的任何值加起来是否为n
【发布时间】:2014-02-10 18:27:07
【问题描述】:

我有一个随机值数组和一个目标值。

#!/bin/bash
objective='50'
declare -a values=(1 2 2 6 8 14.5 15 28.7 .. 42)

我需要找到一种方法来提取数组“值”中加起来为 50 的任意数字组合

数组有重复项和浮点整数。

解决方案集可能如下所示:

50 = 42 + 8
50 = 42 + 6 + 2

最初我从 bash 开始使用一些嵌套的 for 循环,但是我很快意识到这将随着我的数组长度呈指数增长。

我在大学里学过几门 Java 课程,但我对编程仍然缺乏经验。我开始认为这可能需要递归。

有更多编程经验的人能指出我正确的方向吗?
除了嵌套的 for 循环,你还能如何解决这个问题?

【问题讨论】:

  • 您应该将问题的范围缩小到一种语言。
  • 感谢您的提示,我会将问题编辑为 java,因为这是我使用最多的问题
  • 我对其进行了测试并为我的问题添加了完整的源代码(edit1)

标签: java arrays algorithm recursion


【解决方案1】:

这是一个具有时间复杂度的算法O(M*N),而M 是目标,N 是集合的总大小。用背包问题类比如下:-

  1. 背包容量 = 目标
  2. 项目是集合中的元素,其权重和值与自身相同
  3. 使用动态规划计算最大利润
  4. maxprofit = 目标,那么有/有子集与目标相加。
  5. 回溯解决方案。

同样的Java解决方案:-

public class SubSetSum {
    static int[][] costs;

    public static void calSets(int target,int[] arr) {

        costs = new int[arr.length][target+1];
        for(int j=0;j<=target;j++) {
            if(arr[0]<=j) {

                costs[0][j] = arr[0]; 
            }
        }
        for(int i=1;i<arr.length;i++) {

            for(int j=0;j<=target;j++) {
                costs[i][j] = costs[i-1][j];
                if(arr[i]<=j) {
                    costs[i][j] = Math.max(costs[i][j],costs[i-1][j-arr[i]]+arr[i]);
                }
            }

        }

        System.out.println(costs[arr.length-1][target]);
       if(costs[arr.length-1][target]==target) {
           System.out.println("Sets :");
           printSets(arr,arr.length-1,target,"");
       } 

       else System.out.println("No such Set found");

    } 

    public static void printSets(int[] arr,int n,int w,String result) {


        if(w==0) {
            System.out.println(result);
            return;
        }

        if(n==0) {
           System.out.println(result+","+arr[0]);
            return; 
        }

        if(costs[n-1][w]==costs[n][w]) {
            printSets(arr,n-1,w,new String(result));
        }
        if(arr[n]<=w&&(costs[n-1][w-arr[n]]+arr[n])==costs[n][w]) {
            printSets(arr,n-1,w-arr[n],result+","+arr[n]);
        }
    }

    public static void main(String[] args) {
        int[] arr = {1,2,3,8,9,7};
        calSets(10,arr);
    }
}

【讨论】:

    【解决方案2】:

    我会这样做:

    1.一些初始化

    const int N=array size;
    int val[N];   // input data
    bool flag[N];  // is val used ?
    for (int i=0;i<N;i++) flag[i]=false;
    sort val[] descending
    

    2.create function bool find_sum(int s);

    • 如果找到解决方案返回 true,否则返回 false
    • 为所有使用的值设置标志为真

      {
      for (int i=0;i<N;i++)                    // find first usable big number (could be faster with binary search or with tailing last used i index into recursion)
       if ((val[i]<=s)&&(!flag[i]))
        {
        flag[i]=true;                           // flag it as used 
        if (val[i]==s) return true;           // try to find reminder
        if (find_sum(s-val[i])) return true; // if found return true 
        flag[i]=false;                         // else unflag val[i] and continue winth next number 
        }
      return false;                            // if sum not found then return false
      }
      

    3.在 find_sum(s) 之后,您的总和包含所有 val[i] where flag[i]!=false

    [edit1] 功能源测试即使您的案例 [6,5,5] 和 sum=10 也可以

    //---------------------------------------------------------------------------
    int find_sum(int *val,int *use,int N,int sum,bool init=true)
        {
        int i;
        if (init)
            {
            for (i=0;i<N;i++) use[i]=0;         // nothibg used yet
            for (int e=1;e;)                    // bubble sort
             for (e=0,i=1;i<N;i++)
              if (val[i-1]<val[i])
               { e=val[i-1]; val[i-1]=val[i]; val[i]=e; e=1; }
            }
        for (i=0;i<N;i++)                       // find first usable big number (could be faster with binary search or with tailing last used i index into recursion)
         if ((val[i]<=sum)&&(!use[i]))
            {
            use[i]=1;                           // val[i] is used
            if (val[i]==sum) return 1;              // try to find reminder
            if (find_sum(val,use,N,sum-val[i],false)) return 1; // if found return true
            use[i]=0;                           // else val[i] is unused and continue winth next number
            }
        return 0;                               // if sum not found then return false
        }
    //---------------------------------------------------------------------------
    void main()
        {
        int in[]={6,5,5}; // input data
        const int N=sizeof(in)/sizeof(int);
        int ret,out[N];
        if (find_sum(in,out,N,10))
         for (int i=0;i<N;i++)
          if (out[i])
            {
            cout << in[i] << " ";
            }
        }
    //---------------------------------------------------------------------------
    

    附言。在输入数组中的问题中也是浮点值

    • 所以你必须将 int val[],sum 更改为 float/double
    • 并为总和比较添加一些准确性以使用浮点数

      if (val[i]==sum) return 1;
      
    • 改成

      if (fabs(val[i]-sum)<1e-10) return 1;
      
    • 或使用任何其他精度代替 1e-10

    【讨论】:

    • 不是这个 ...
    • 发生了什么?你删除了评论还是我不小心用我的评论编辑了它?请把它加回来很高兴看到其他人看到的所有可能的缺点
    【解决方案3】:

    您可以使用递归是的,您可以将数组分成子部分(我使用List)。

    1. 从父列表的第 0 个索引和一个空白列表开始
    2. i+1 迭代到子列表你的父级,从而从0 to i 增加你的工作列表
    3. 检查sum(计算)是否等于您的目标

    代码:

    static Integer[] array = { 1, 2, 2, 6, 8, 14, 15, 28, 30, 32, 12, 48, 6, 42 };
    static int objective = 50;
    
    public static void main(String args[]) {
        add(new ArrayList<Integer>(Arrays.asList(array)),
                new ArrayList<Integer>());
    }
    
    public static void add(List<Integer> digits, List<Integer> workingList) {
    
        for (int i = 0; i < digits.size(); i++) {
            // New sublist to store values from 0 to i
            List<Integer> list = new ArrayList<Integer>(workingList);
            list.add(digits.get(i));
    
            // Here you call this recursively with your Parent list from i+1
            // index and working list from 0 to i
            add(digits.subList(i + 1, digits.size()), list);
        }
    
        int sum = 0;
        for (int element : workingList) {
            sum += element;
        }
    
        if (sum == objective) {
            System.out.println(objective + " = "
                    + Arrays.toString(workingList.toArray()));
        }
    
    }
    

    输出:

    50 = [1, 2, 2, 15, 30]
    50 = [1, 2, 6, 8, 15, 12, 6]
    50 = [1, 2, 6, 14, 15, 12]
    50 = [1, 2, 14, 15, 12, 6]
    50 = [1, 2, 15, 32]
    50 = [1, 2, 6, 8, 15, 12, 6]
    ...
    

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 2017-06-28
      • 1970-01-01
      • 1970-01-01
      • 2021-12-26
      • 2011-09-15
      • 2022-08-11
      • 2021-04-28
      • 1970-01-01
      相关资源
      最近更新 更多