本章包括的题目有:
1.两数之和
思路解析:
由于要在一堆无序的数中找到两个数的和为target,只需先拿到一个值,然后匹配有没有另一个即可。由于需要返回下标,我们可以用哈希表来表示一个元素的值和下标。
遍历数组 nums,对于当前元素 nums[i]。检查哈希表中是否已存在一个值与之和为target。若存在,说明之前遍历过的某个数与当前数之和等于目标值,直接返回这两个数的索引。若不存在,将当前元素 (nums[i], i) 存入哈希表,供后续元素匹配。题目保证有且仅有一个有效解,因此循环内一定会返回结果。
代码实现:
java
class Solution {
public int[] twoSum(int[] nums, int target) {
HashMap<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]; // 根据题目约定,此处不会执行到
}
}
时间复杂度O(n)
空间复杂度O(n)
2.字母的异位词分组
思路解析:
由于要对一堆字符串按照字母异位词分组,只需将每个字符串的字符排序后作为唯一标识,相同标识的字符串属于同一组。由于需要返回分组结果,我们可以用哈希表来表示一个排序后的字符串(键)和对应的原字符串列表(值)。
遍历字符串数组 strs,对于当前字符串 strs[i]:将其转换为字符数组并排序,再转换回字符串作为键 key。检查哈希表中是否已存在该键:若存在,将当前字符串添加到对应的列表中;若不存在,则先创建一个新列表再添加。最后,哈希表中所有的 value 集合即为分组结果,直接转换为 ArrayList 返回。题目不要求保持顺序,因此无需额外处理。
代码实现:
java
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
int n = strs.length;
Map<String, List<String>> map = new HashMap<>();
for(int i = 0;i < n;i ++){
char[] chars = strs[i].toCharArray();
Arrays.sort(chars);
String key = new String(chars);
map.computeIfAbsent(key,k -> new ArrayList<>()).add(strs[i]);
}
return new ArrayList<>(map.values());
}
}
computeIfAbsent方法会先查找是否有key,若有则获得其value(顺序表),若没有就添加key到map中,并通过后面的计算函数得到一个value存入map中作为新添加的key的值(此处为一个空顺序表),再通过add方法将对应的字符串添加其中。
map.values()的返回值是一个Collection,而不是List,所以不可以直接返回,而ArrayList的构造器可以接受Collection,所以可以构造成ArrayList再返回。
时间复杂度O( n * L log L ) //n为字符串数组的长度,L为字符串平均长度
空间复杂度O( n * L)
3.最长连续序列
思路解析:
由于要在无序数组中找到最长连续序列的长度,最朴素的想法是先排序,然后遍历。但是要求时间复杂度 O(n),因此不能做排序处理,我们可以用一个哈希集合来去重和匹配相邻的数。
我们只需将所有数字存入哈希集合,然后遍历集合中的每个数字。对于当前数字 n,若它的前驱 n-1 不存在于集合中,则说明 n 是一个连续序列的起点。从该起点开始,不断检查集合中是否存在 n+1、n+2......并累加计数。这样每个元素最多被访问两次(一次作为起点向后扩展,一次作为非起点被跳过),总体线性。最终返回最大计数即可。
代码实现:
java
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for(int num : nums){
set.add(num);
}
int result = 0;
for (Integer n : set) {
int mid = 1; //进循环说明当前数一定存在于原数组,所以从1开始记录结果
if(set.contains(n - 1)){
continue;
}
while(set.contains(n + 1)){
mid ++;
n ++;
}
if(mid > result) result = mid;
}
return result;
}
}
时间复杂度O(n)
空间复杂度O(n)
下一章: