1. 两数之和
暴力枚举
- 时间复杂度为
O(n^2)
的解法为遍历数组,每遍历到一个元素x
,再进行二次循环,找到元素为target-x
的index。
public static int[] twoSum1(int[] nums, int target) {
int[] res = new int[2];
for (int i = 0; i < nums.length-1; i++) {
for (int j = i+1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
res[0] = i;
res[1] = j;
}
}
}
return res;
}
- 然而,这是最初的解法,时间复杂度:
O(n^2)
,空间复杂度:O(1)
- 当在寻找
target-x
元素时,时间复杂度过高,而哈希表可以将时间复杂度从O(n)
降到O(1)
,因此可以使用HashMap来降低复杂度。
哈希表
- 使用HashMap的key存储index,使用value存储值。当遍历到一个元素
x
,我们从哈希表中查找是否可以找到元素为target-x
的元素,将元素x
存入哈希表,即可保证不会和自己x
匹配。
- 时间复杂度:
O(n)
,空间复杂度:O(n)
public static int[] twoSum(int[] nums, int target) {
int[] res = new int[2];
HashMap<Integer,Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int temp = target - nums[i];
if (map.containsKey(temp)) {
res[0] = i;
res[1] = map.get(temp);
}
map.put(nums[i],i);
}
return res;
}
49. 字母异位词分组
解题思路1: 排序
- 解题关键在于:对于异位词来说,应该都有个关键的标志。在这里,我们将字符数组排序后的字符串作为区分异位词的标志。
- 例如:
eat,ate,tea
,这三个词排序后都应该为aet
,即他们本质是相同的。
- 因此,我们可以使用哈希表,key为排序后的string,value为满足该标志的异位词
eat,ate,tea
public static List<List<String>> groupAnagrams1(String[] strs) {
HashMap<String,List<String>> map = new HashMap<>();
for (String str : strs) {
char[] arr = str.toCharArray();
Arrays.sort(arr);
String key = String.valueOf(arr);
if (!map.containsKey(key)) {
map.put(key, new ArrayList<>());
}
map.get(key).add(str);
}
return new ArrayList<>(map.values());
}
解题思路2:计数
- 由于使用排序时间复杂度较大,因此需要进行改进。
- 第一种方法我们使用排序后的字符串(
aet
)作为key,第2种我们使用字符+字符频次(a1e1t1
)这种的作为标志。
public static List<List<String>> groupAnagrams2(String[] strs) {
HashMap<String,List<String>> map = new HashMap<>();
for (String str : strs) {
int[] counts = new int[26];
for (int i = 0; i < str.length(); i++) {
counts[str.charAt(i)-'a']++;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 26; i++) {
if (counts[i] > 0) {
sb.append((char) (i + 'a')).append(counts[i]);
}
}
if (!map.containsKey(sb.toString())) {
map.put(sb.toString(),new ArrayList<>());
}
map.get(sb.toString()).add(str);
}
return new ArrayList<>(map.values());
}
128.最长连续序列
哈希表
- 使用哈希表来存储元素与该元素的最长连续序列长度
- 当有新元素时,计算该元素的left和right的最长连续序列长度
len
,则leftLen+rightLen+1
为该元素的最长连续序列长度maxLen
。
- 最后,我们每计算一次,都要更新该元素
x
的value为maxLen
,更新左边界(x-leftLen
)的value为maxLen
,更新右边界(x-rightLen
)的value为maxLen
。
public static int longestConsecutive(int[] nums) {
HashMap<Integer,Integer> map = new HashMap();
int maxLen = 0;
for (int i = 0; i < nums.length; i++) {
if (!map.containsKey(nums[i])) {
int left = map.getOrDefault(nums[i]-1,0);
int right = map.getOrDefault(nums[i]+1,0);
int len = 1 + left + right;
if (len > maxLen)
maxLen = len;
map.put(nums[i],len);
if (left > 0)
map.put(nums[i]-left, len);
if (right > 0)
map.put(nums[i]+right, len);
}
}
return maxLen;
}