1.两数之和
根据题目描述,我们采用哈希表的解法,可以将时间复杂度降到o(n)
核心思路
一边遍历,一边查表:
- 遍历数组时,计算当前数字需要的"另一半"(
diff = target - nums[i]) - 如果
diff已经在哈希表中,说明之前遇到过,直接返回两个索引 - 如果没遇到过,把当前数字存入哈希表,供后面使用
class Solution {
public int[] twoSum(int[] nums, int target) {
// 哈希表:key = 数字值,value = 该数字在数组中的索引
HashMap<Integer, Integer> map = new HashMap<>();
int n = nums.length;
// 遍历数组
for (int i = 0; i < n; i++) {
// 计算当前数字需要的"另一半"
int diff = target - nums[i];
// 检查这个"另一半"是否已经出现过
if (map.containsKey(diff)) {
// 找到了!返回之前数字的索引和当前索引
return new int[]{map.get(diff), i};
} else {
// 没找到,把当前数字存入哈希表,供后续使用
map.put(nums[i], i);
}
}
// 题目保证有解,实际不会执行到这里
return null;
}
}
详细注释已经写上。
2.字母异位词分组
核心思路
识别异位词的关键:
"eat"、"tea"、"ate"都是异位词- 把它们按字母排序后,都变成
"aet" - 用排序后的字符串作为哈希表的 key,异位词都放入同一个 key 对应的列表
public List<List<String>> groupAnagrams(String[] strs) {
// 哈希表:key = 排序后的字符串,value = 异位词列表
HashMap<String, List<String>> map = new HashMap<>();
for (String str : strs) {
// 1. 将当前字符串转为字符数组并排序
char[] chars = str.toCharArray();
Arrays.sort(chars); // 例如 "eat" → ['a','e','t']
// 2. 排序后的字符数组转回字符串作为 key
String sortedKey = new String(chars); // "aet"
// 3. 检查 key 是否已存在
if (map.containsKey(sortedKey)) {
// 存在:取出列表,添加当前字符串
List<String> list = map.get(sortedKey);
list.add(str);
} else {
// 不存在:创建新列表,添加当前字符串
ArrayList<String> list = new ArrayList<>();
list.add(str);
map.put(sortedKey, list);
}
}
// 4. 返回所有 value(每个 value 是一个异位词组)
return new ArrayList<>(map.values());
}
}
3.最长连续序列
我们用两种方法来解决该题
(1)排序法
class Solution {
public int longestConsecutive(int[] nums) {
int n = nums.length;
if (n == 0) return 0;
Arrays.sort(nums); // 排序让连续数字相邻
int res = 1; // 最终结果
int maxLen = 1; // 当前连续长度
for (int i = 1; i < n; i++) {
if (nums[i] == nums[i-1]) {
continue; // 重复数字跳过
} else if (nums[i] == nums[i-1] + 1) {
maxLen++; // 连续,长度+1
res = Math.max(res, maxLen);
} else {
maxLen = 1; // 断开,重置长度
}
}
return res;
}
}
(2)使用哈希表
public int longestConsecutive(int[] nums) {
if (nums == null || nums.length == 0) return 0;
// 1. 所有数字放入 HashSet,去重 + O(1) 查找
HashSet<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int longest = 0;
// 2. 遍历每个数字
for (int num : set) {
// 关键:只从连续序列的起点开始找
// 如果 num-1 存在,说明 num 不是起点,跳过
if (!set.contains(num - 1)) {
// num 是起点
int currentNum = num;
int currentLen = 1;
// 向后查找连续数字
while (set.contains(currentNum + 1)) {
currentNum++;
currentLen++;
}
longest = Math.max(longest, currentLen);
}
}
return longest;
}
}
两种方法的对比