题目
主要思路
首先,上来第一眼看是一个很简单的排列组合问题,但是暴力算法肯定是超时的。废话不多说,上代码。
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args)
{
Scanner in =new Scanner(System.in);
int N,i,temp,tt;
N=in.nextInt();
int[] num=new int[N];
for ( i = 0; i < N; i++)
num[i]=in.nextInt();
Set<Integer> contain =new HashSet<>();
List<Integer> a =new LinkedList<>(); //存放中间变量,一次遍历中,容器不存在 的数
contain.add(Integer.valueOf(num[0])); //先将第一个元素填入到容器
for(i=1;i<N;i++)
{
for (Iterator<Integer> iter =contain.iterator();iter.hasNext();) {
tt=iter.next().intValue();
temp=tt+num[i];
if(temp!=0&&temp<100000&&!contain.contains(Integer.valueOf(temp)))
a.add(Integer.valueOf(temp));
temp=tt-num[i];
temp=Math.abs(temp); //砝码差的绝对值
if(temp!=0&&temp<100000&&!contain.contains(Integer.valueOf(temp))&&!a.contains(Integer.valueOf(temp)))
a.add(Integer.valueOf(temp));
}
contain.addAll(a);
a.clear();
if(!contain.contains(Integer.valueOf(num[i])))
contain.add(Integer.valueOf(num[i]));
}
System.out.println(contain.size());
}
}
记录一下自己第一次全部AC,可能有更好的思路,但是下面还是讲一下我的思路吧!
思路
首先,对于这种需要很多组合的问题,肯定是动态规划了。首先将第一个砝码放入右边,目前只有一种组合。继续放入第二个砝码,你可以选择继续放到右边或者左边。放入右边其实逻辑上就是砝码A+砝码B,放入左边就是砝码A-砝码B结果的绝对值。剩下的就是重复一直放入砝码。
在代码实现中,我选择的数据结构是HashSet和LinkedList。HashSet用于存放加完砝码的结果。而LinkedList用于存放加砝码时的不确定砝码值。
为什么不直接将加完的值全放进HashSet中,非得加一个LinkedList。因为如果直接加入,那么就对上一次的砝码称重的结果,造成了影响。意思就是,你刚加出来的结果,有会被踢出去,被这个重量的砝码再运算一次。
例如:
HashSet : 1 2 4
这次要加入的砝码是 6
首先1 + 6 = 7
那么HashSet: 1 2 4 7
到最后 7 + 6 = 13
HashSet: 1 2 4 7 13
实际上,这里的6用了两次,你把用这次砝码6运算出来的结果7,又加了一次6,变成了13.显然,这个结果是错误的。
我选择将一次迭代的结果,先放在LinkedList容器中,最终一并放入HashSet中.
第二次代码
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
public class Main {
public static void main(String[] args)
{
Scanner in =new Scanner(System.in);
int N,i,temp,tt;
N=in.nextInt();
int[] num=new int[N];
for ( i = 0; i < N; i++)
num[i]=in.nextInt();
Set<Integer> contain =new HashSet<>();
Set<Integer> a =new HashSet<>(); //存放中间变量,一次遍历中,容器不存在 的数
contain.add(Integer.valueOf(num[0])); //先将第一个元素填入到容器
for(i=1;i<N;i++)
{
for (Iterator<Integer> iter =contain.iterator();iter.hasNext();) {
tt=iter.next().intValue();
temp=tt+num[i];
if(temp!=0&&temp<100000)
a.add(Integer.valueOf(temp));
temp=tt-num[i];
temp=Math.abs(temp);
if(temp!=0&&temp<100000)
a.add(Integer.valueOf(temp));
}
contain.addAll(a);
a.clear();
if(!contain.contains(Integer.valueOf(num[i])))
contain.add(Integer.valueOf(num[i]));
}
System.out.println(contain.size());
}
}
最新的改进:
很明显if语句中的限制条件变少了。因为我运用HashSet的性质,无序、不可重复。使用两个HashSet,每次运算的结果。不用再判断在原来出现过!直接将所以的结果都加入,如果重复会直接加入失败。
第一版本的代码是用contains( )方法去判断,是否在原来的容器中出现,HashSet对于查找效率很高,使用HashSet直接添加,他会先查找是否先前存在该值,明显的HashSet查找的效率会快于contains( )方法。
全部AC的感觉太棒了!!!