1 两数之和
难度:简单
题目描述
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。
示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]
示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]
提示:
2 <= nums.length <= 104-109 <= nums[i] <= 109-109 <= target <= 109只会存在一个有效答案
进阶:你可以想出一个时间复杂度小于 O(n2) 的算法吗?
思路 - 初见
空间换时间,哈希存储,键为nuns[i] ,值为i ,即下标,遍历数组 ,检查哈希表中target - nums[i]的值是否存在,若存在,返回结果
代码 - 初见
class Solution {
public int[] twoSum(int[] nums, int target) {
// Key: 数值, Value: 对应的下标
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
map.put(nums[i], i);
int complement = target - nums[i];
// 检查差值是否已经在哈希表中
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
}
// 如果没有找到匹配项,返回空数组
return new int[0];
}
}问题
存在自己加自己的问题。
解决:写入同一个循环,边检查边写入。
代码 - 改进
class Solution {
public int[] twoSum(int[] nums, int target) {
// Key: 数值, Value: 对应的下标
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
// 检查差值是否已经在哈希表中
if (map.containsKey(complement)) {
return new int[] { map.get(complement), i };
}
// 如果不在,将当前数值和索引存入表中
map.put(nums[i], i);
}
// 如果没有找到匹配项,返回空数组
return new int[0];
}
}2 字母异位词分组
难度:中等
题目描述
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。
示例 1:
输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]
输出: [["bat"],["nat","tan"],["ate","eat","tea"]]
解释:
在
strs中没有字符串可以通过重新排列来形成"bat"。字符串
"nat"和"tan"是字母异位词,因为它们可以重新排列以形成彼此。字符串
"ate","eat"和"tea"是字母异位词,因为它们可以重新排列以形成彼此。
示例 2:
输入: strs = [""]
输出: [[""]]
示例 3:
输入: strs = ["a"]
输出: [["a"]]
提示:
1 <= strs.length <= 1040 <= strs[i].length <= 100strs[i]仅包含小写字母
思路 - 初见
采用哈希存储,键为组成字符串的字符组,值为组成的字符串组
存储键时需要将字母排序,暂时没有想到改进方法
输出时输出值对应的数组即可
代码 - 初见
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// 创建哈希表:Key 存储排序后的“标准”字符串,Value 存储对应的异位词列表
Map<String, List<String>> hashMap = new HashMap<>();
for (String str : strs) {
// 1. 将当前字符串转换为字符数组
char[] chars = str.toCharArray();
// 2. 对字符进行排序
Arrays.sort(chars);
// 3. 将排序后的字符数组转回字符串,作为 HashMap 的 Key
String str_s = String.valueOf(chars);
// 4. 判断逻辑:如果 Key 已存在,直接获取 List 并添加;否则创建新 List
if (hashMap.containsKey(str_s)) {
// 已有该组,直接追加
hashMap.get(str_s).add(str);
} else {
// 新的组,初始化后再存入
List<String> list = new ArrayList<>();
list.add(str);
hashMap.put(str_s, list);
}
}
// 5. 利用 HashMap 的 values() 方法构造最终的嵌套列表
return new ArrayList<>(hashMap.values());
}
}问题
可以加入边界条件检查
代码 - 改进
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
// 检查边界条件
if (strs == null || strs.length == 0) {
return new ArrayList<>();
}
// 创建哈希表:Key 存储排序后的“标准”字符串,Value 存储对应的异位词列表
Map<String, List<String>> hashMap = new HashMap<>();
for (String str : strs) {
// 1. 将当前字符串转换为字符数组
char[] chars = str.toCharArray();
// 2. 对字符进行排序
Arrays.sort(chars);
// 3. 将排序后的字符数组转回字符串,作为 HashMap 的 Key
String str_s = String.valueOf(chars);
// 4. 判断逻辑:如果 Key 已存在,直接获取 List 并添加;否则创建新 List
if (hashMap.containsKey(str_s)) {
// 已有该组,直接追加
hashMap.get(str_s).add(str);
} else {
// 新的组,初始化后再存入
List<String> list = new ArrayList<>();
list.add(str);
hashMap.put(str_s, list);
}
}
// 5. 利用 HashMap 的 values() 方法构造最终的嵌套列表
return new ArrayList<>(hashMap.values());
}
}3 最长连续序列
难度:中等
题目描述
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。
请你设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。示例 2:
输入:nums = [0,3,7,2,5,8,4,6,0,1]
输出:9
示例 3:
输入:nums = [1,0,1,2]
输出:3
提示:
0 <= nums.length <= 105-109 <= nums[i] <= 109
思路 - 初见
依旧哈希,先存再找,这次只需存值
先遍历存储到哈希表中
不断查找下一个数是否存在记录长度——若数字之前还有序列会浪费时间
先检查数字的前一个数是否存在,若存在,直接跳过
若长度超过length/2,必为最长(这题貌似用不上)
代码 - 初见
class Solution {
public int longestConsecutive(int[] nums) {
// 边界判断
if (nums.length == 0) return 0;
Set<Integer> set = new HashSet<>();
for (int i = 0; i < nums.length; i++) {
// 将数字存入set
set.add(nums[i]);
}
int maxLength = 0;
for (int i = 0; i < nums.length; i++) {
// 非数字起点,直接跳过
if (set.contains(nums[i] - 1)) {
continue;
}
int length = 1;
int start = nums[i];
while (set.contains(start + 1)) {
start++;
length++;
}
if (length > maxLength) {
maxLength = length;
}
}
return maxLength;
}
}问题
在处理超大数组时,出现了超时问题
改进:第二次遍历哈希集合而非数组,减少重复遍历问题
一个连续字段遍历结束时,start - 起点即为长度,可以减少length记录
代码 - 改进
class Solution {
public int longestConsecutive(int[] nums) {
// 边界判断
if (nums == null || nums.length == 0) return 0;
// 1. 去重并提供 O(1) 查询
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int maxLength = 0;
// 2. 改进点:遍历 set 而不是 nums
// 这样可以确保每个数字及其逻辑只被处理一次,不受原数组重复项干扰
for (int num : set) {
if (!set.contains(num - 1)) {
int start = num + 1;
while (set.contains(start)) {
start++;
}
maxLength = Math.max(maxLength, start - num);
}
}
return maxLength;
}
}