第一天
对于寻找两数之和,不用双指针的话要用hashmap
在Java中,Map
、Set
和List
是三个不同的集合接口,分别用于不同的场景,它们的核心区别和操作方法如下:
1. 核心区别
特性 | List | Set | Map |
---|---|---|---|
有序性 | 有序(按插入顺序或索引) | 无序(但LinkedHashSet 、TreeSet 例外) | 无序(但LinkedHashMap 、TreeMap 例外) |
元素唯一性 | 允许重复元素 | 不允许重复元素 | 键(Key)唯一,值(Value)可重复 |
访问方式 | 通过索引访问(get(index) ) | 只能遍历或迭代访问 | 通过键(Key)访问值(get(key) ) |
典型实现类 | ArrayList , LinkedList | HashSet , TreeSet , LinkedHashSet | HashMap , TreeMap , LinkedHashMap |
2. 存值函数和取值函数
List(列表)
- 存值函数:
add(E element)
:在列表末尾添加元素。add(int index, E element)
:在指定索引处插入元素。set(int index, E element)
:替换指定索引处的元素。
- 取值函数:
get(int index)
:根据索引获取元素。iterator()
:返回迭代器遍历所有元素。
示例:
List<String> list = new ArrayList<>();
list.add("A"); // 添加元素到末尾
list.add(0, "B"); // 在索引0处插入元素
String value = list.get(0); // 获取索引0处的元素("B")
Set(集合)
- 存值函数:
add(E element)
:添加元素(如果元素已存在,返回false
)。
- 取值函数:
- 没有直接通过索引或键的取值方法,只能通过遍历或迭代器访问元素。
iterator()
:返回迭代器遍历所有元素。contains(Object o)
:检查元素是否存在。
示例:
Set<String> set = new HashSet<>();
set.add("A");
set.add("B");
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String element = it.next(); // 遍历元素
}
Map(映射)
- 存值函数:
put(K key, V value)
:添加键值对(若键已存在,则覆盖旧值)。putAll(Map<? extends K, ? extends V> m)
:添加多个键值对。
- 取值函数:
get(Object key)
:根据键获取对应的值。keySet()
:获取所有键的集合(返回Set<K>
)。values()
:获取所有值的集合(返回Collection<V>
)。entrySet()
:获取所有键值对的集合(返回Set<Map.Entry<K, V>>
)。
示例:
Map<String, Integer> map = new HashMap<>();
map.put("A", 1);
map.put("B", 2);
int value = map.get("A"); // 根据键"A"获取值(1)
Set<String> keys = map.keySet(); // 获取所有键
3. 总结
- List:有序,允许重复,通过索引操作元素。
- Set:无序(部分实现有序),不允许重复,无索引。
- Map:键值对结构,键唯一,通过键操作值。
根据具体需求选择集合类型:
- 需要保留插入顺序且允许重复?用
List
(如ArrayList
)。 - 需要去重?用
Set
(如HashSet
)。 - 需要键值关联?用
Map
(如HashMap
)。
第二天
一、集合框架核心区别与操作
1. Map、Set、List三者的区别
```java
// 创建示例
List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<String, Integer> map = new HashMap<>();
// 核心区别
| 特性 | List | Set | Map |
|---------------|--------------------|--------------------|--------------------|
| 有序性 | 是(插入顺序/索引) | 否(LinkedHashSet除外) | 否(LinkedHashMap除外) |
| 元素唯一性 | 允许重复 | 不允许重复 | Key唯一,Value可重复 |
| 访问方式 | get(index) | 只能迭代遍历 | get(key) |
| 典型实现类 | ArrayList, LinkedList | HashSet, TreeSet | HashMap, TreeMap |
2. 集合操作方法对比
Map常用方法
// 安全取值操作
String value = map.getOrDefault("key", "default");
// 高效分组操作(字母异位词案例)
map.computeIfAbsent(sortedStr, k -> new ArrayList<>()).add(originalStr);
Set元素遍历技巧
// 推荐遍历方式
Set<Integer> set = new HashSet<>();
// 增强for循环
for (Integer num : set) { /* ... */ }
// 迭代器遍历
Iterator<Integer> it = set.iterator();
二、字符串处理关键点
1. StringBuffer vs StringBuilder
// 性能测试对比(10000次拼接)
StringBuffer耗时:5ms
StringBuilder耗时:3ms
// 选择建议
- 单线程场景:优先使用StringBuilder
- 多线程共享资源:必须使用StringBuffer
2. 字符ASCII码操作
// 字母频率统计技巧
int[] count = new int;
for (char c : str.toCharArray()) {
count[c - 'a']++; // 将字符映射到0-25的索引
}
三、算法问题典型解决方案
1. 字母异位词分组(LeetCode 49)
错误修正重点
// 错误示例:键生成方式不唯一
sb.append(counts[i]); // 可能产生哈希冲突
// 正确实现
// 方法1:排序法(O(nklogk))
char[] chars = str.toCharArray();
Arrays.sort(chars);
String key = new String(chars);
// 方法2:计数法(O(nk))
StringBuilder sb = new StringBuilder();
sb.append((char)('a' + i)).append(counts[i]);
2. 最长连续序列(LeetCode 128)
优化解法
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) set.add(num);
int maxStreak = 0;
for (int num : set) {
// 关键优化:仅处理序列起点
if (!set.contains(num - 1)) {
int currentNum = num;
int currentStreak = 1;
while (set.contains(currentNum + 1)) {
currentNum++;
currentStreak++;
}
maxStreak = Math.max(maxStreak, currentStreak);
}
}
return maxStreak;
}
四、常见错误与调试经验
1. 集合操作典型错误
// 错误:直接使用containsValue判断分组
if (map.containsValue(value)) // 可能误判哈希冲突
// 正确:使用排序后的字符串作为Key
2. 空指针异常预防
// 必须处理空输入情况
if (nums == null || nums.length == 0) return 0;
// 集合判空操作
if (set.isEmpty()) return Collections.emptyList();
五、最佳实践总结
-
集合选择原则
- 需要索引访问 → ArrayList
- 需要去重 → HashSet
- 需要键值对 → HashMap
-
字符串处理
- 单线程拼接 → StringBuilder
- 频繁修改字符串 → 字符数组操作
-
算法优化方向
- 空间换时间:合理使用HashSet/HashMap
- 避免冗余计算:利用排序预处理
- 边界条件处理:空输入、单个元素等情况
-
代码质量
- 优先使用Java 8+ API(如computeIfAbsent)
- 重要位置添加防御性空值检查
- 复杂算法添加注释说明核心逻辑
// 防御性编程示例
public List<List<String>> groupAnagrams(String[] strs) {
if (strs == null || strs.length == 0)
return Collections.emptyList();
// ...核心逻辑...
}