1. 题目
读题
考查点
2. 解法
思路
- 1. 暴力破解,3重循环
- 2. 利用set 去重
可参照
【Java 数据结构及算法实战】系列 045:HJ41 称砝码-华为开发者论坛 | 华为开发者联盟 (huawei.com)
代码逻辑
具体实现
public class HJ041 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] w = new int[n];
for (int i = 0; i < n; i++) {
w[i] = sc.nextInt();
}
int[] nums = new int[n];
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
System.out.println(getWays(w, nums, n));
}
public static int getWays(int[] w, int[] nums, int n) {
Set<Integer> set = new HashSet<>();
set.add(0);
for (int i = 0; i < n; i++) {
List<Integer> list = new ArrayList<>(set);
for (int j = 0; j <= nums[i]; j++) {
for (int k = 0; k < list.size(); k++) {
set.add(list.get(k) + j * w[i]);
}
}
}
return set.size();
}
}
3. 总结
3.1 java 中 set 在add 时如果重了会怎么办
java 中的 set 集合在 add 时如果有重复的元素,会自动忽略掉,不会添加到集合中。这是 set 集合的特点,它只能存储不重复的元素。
如果你想要存储重复的元素,你可以考虑使用其他的集合类型,比如 list 或者 multiset。这些集合类型可以允许有重复的元素存在。
3.2 set.add 会报错吗
set.add 一般不会报错,除非你添加了不支持的元素,比如 null 或者类型不匹配的元素。但是 set.add 有可能返回 false,表示添加失败,这是因为 set 集合不能有重复的元素,如果你添加了一个已经存在的元素,它会被忽略掉。
3.3 set 几个实现类
- HashSet:使用哈希表来存储元素,性能最好,但是不保证元素的顺序。
- TreeSet:使用红黑树来存储元素,按照元素的值来排序,性能较差,但是可以使用 SortedSet 接口的操作。
- LinkedHashSet:使用哈希表和链表来存储元素,按照元素的插入顺序来排序,性能略低于 HashSet,但是可以保证元素的顺序。
- EnumSet:使用位向量来存储枚举类型的元素,性能非常高,但是只能用于枚举类型。
除了这些通用的 set 实现类,还有一些特殊用途的 set 实现类,比如 CopyOnWriteArraySet, ConcurrentSkipListSet, ImmutableSet 等。你可以根据你的需求和场景来选择合适的 set 实现类。
3.4 如何选择合适的 set 实现类?
如何选择合适的 set 实现类,主要取决于你对 set 的需求和场景。一般来说,你可以根据以下几个方面来考虑:
- 元素的顺序:如果你不关心元素的顺序,你可以使用 HashSet,它是性能最好的 set 实现类,但是不保证元素的顺序。如果你需要按照元素的值来排序,你可以使用 TreeSet,它可以使用 SortedSet 接口的操作,但是性能较差。如果你需要按照元素的插入顺序来排序,你可以使用 LinkedHashSet,它可以保证元素的顺序,性能略低于 HashSet。
- 元素的类型:如果你的元素是枚举类型,你可以使用 EnumSet,它是一个专门为枚举类型设计的高性能 set 实现类,它使用位向量来存储元素,非常节省空间。
- 集合的大小:如果你的集合很大或者不确定大小,你需要考虑 set 实现类的容量和负载因子。容量是指 set 内部存储结构的大小,负载因子是指容量和元素数量之间的比例。一般来说,容量越大,空间消耗越高,但是避免了频繁地扩容和复制数据结构;负载因子越高,空间利用率越高,但是增加了哈希冲突和查找时间。HashSet 和 LinkedHashSet 都有容量和负载因子这两个参数,你可以根据你的需求来调整它们。TreeSet 和 EnumSet 没有这两个参数。
- 并发访问:如果你需要在多线程环境下访问 set 集合,你需要考虑并发安全问题。一般来说,普通的 set 实现类都不是线程安全的,如果你需要线程安全的 set 实现类,你可以使用 CopyOnWriteArraySet 或者 ConcurrentSkipListSet。CopyOnWriteArraySet 是一个基于数组的线程安全的 set 实现类,它在每次修改操作时都会复制一个新的数组,适合读多写少的场景。ConcurrentSkipListSet 是一个基于跳表的线程安全的 set 实现类,它支持并发访问和排序操作,适合读写均衡的场景。