LeeCode刷题经验

第一天

对于寻找两数之和,不用双指针的话要用hashmap
在Java中,MapSetList是三个不同的集合接口,分别用于不同的场景,它们的核心区别和操作方法如下:


1. 核心区别

特性ListSetMap
有序性有序(按插入顺序或索引)无序(但LinkedHashSetTreeSet例外)无序(但LinkedHashMapTreeMap例外)
元素唯一性允许重复元素不允许重复元素键(Key)唯一,值(Value)可重复
访问方式通过索引访问(get(index)只能遍历或迭代访问通过键(Key)访问值(get(key)
典型实现类ArrayList, LinkedListHashSet, TreeSet, LinkedHashSetHashMap, 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();

五、最佳实践总结

  1. 集合选择原则

    • 需要索引访问 → ArrayList
    • 需要去重 → HashSet
    • 需要键值对 → HashMap
  2. 字符串处理

    • 单线程拼接 → StringBuilder
    • 频繁修改字符串 → 字符数组操作
  3. 算法优化方向

    • 空间换时间:合理使用HashSet/HashMap
    • 避免冗余计算:利用排序预处理
    • 边界条件处理:空输入、单个元素等情况
  4. 代码质量

    • 优先使用Java 8+ API(如computeIfAbsent)
    • 重要位置添加防御性空值检查
    • 复杂算法添加注释说明核心逻辑
// 防御性编程示例
public List<List<String>> groupAnagrams(String[] strs) {
    if (strs == null || strs.length == 0) 
        return Collections.emptyList();
    // ...核心逻辑...
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值