Day 26:哈希 + 双指针
49. 字母异位词分组 - 力扣(LeetCode)
一开始出错,使用了List作为键,但是List都是不一样的。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<List<Character>, List<String>> map = new HashMap<>();
for(int i = 0; i < strs.length; i++){
List<Character> list = new LinkedList<>();
for(int j = 0; j < strs[i].length(); j++){
list.add(strs[i].charAt(j));
}
if(map.containsKey(list) == false){
List<String> str = new LinkedList<>();
str.add(strs[i]);
map.put(list, str);
} else {
map.get(list).add(strs[i]);
}
}
List<List<String>> res = new LinkedList<>();
Set<List<Character>> keys = map.keySet();
for (List<Character> list : keys) {
res.add(map.get(list));
}
return res;
}
}
解决方法:修改键值为String。
class Solution {
public List<List<String>> groupAnagrams(String[] strs) {
HashMap<String, List<String>> map = new HashMap<>();
for(int i = 0; i < strs.length; i++){
char[] chars = strs[i].toCharArray();
Arrays.sort(chars);
String key = new String(chars);
if(map.containsKey(key) == false){
List<String> str = new LinkedList<>();
str.add(strs[i]);
map.put(key, str);
} else {
map.get(key).add(strs[i]);
}
}
List<List<String>> res = new LinkedList<>();
Set<String> keys = map.keySet();
for (String s : keys) {
res.add(map.get(s));
}
return res;
}
}
没想到这么简单一个题目拖了这么久。而且哈希里的很多操作并不熟悉。
128. 最长连续序列 - 力扣(LeetCode)
一开始想着排序做,时间复杂度O(nlogn)但是这是在哈希表里面的题目。
用哈希表记录数据,遍历哈希表,如果存在后一位数,就++,不断更新最大长度。
class Solution {
public int longestConsecutive(int[] nums) {
int max = 0;
HashSet<Integer> set = new HashSet<>();
for(int i = 0; i < nums.length; i++){
set.add(nums[i]);
}
for(int num : set){
if(!set.contains(num - 1)){
int currentNum = num;
int currentLength = 1;
while(set.contains(currentNum + 1)){
currentLength++;
currentNum++;
}
max = Math.max(max, currentLength);
}
}
return max;
}
}
11. 盛最多水的容器 - 力扣(LeetCode)
双指针题目
class Solution {
public int maxArea(int[] height) {
int l = 0;
int r = height.length - 1;
int max = 0;
while(l < r){
max = Math.max(max,Math.min(height[l],height[r])*(r - l));
if(height[l] < height[r]){
l++;
} else {
r--;
}
}
return max;
}
}
有一点贪心的思想,用while简化了两个for循环,因为我们每次都取更长的板,那种可能会让结果更小的可能性我们就不考虑了。从而降低复杂度。
15. 三数之和 - 力扣(LeetCode)
暴力写就是查找,会超时
改成二分查找降低时间复杂度:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0; i < nums.length; i ++){
if (i > 0 && nums[i] == nums[i - 1]) continue; // 外层去重
int l = i + 1;
int r = nums.length - 1;
int target = -nums[i];
while(l < r){
int sum = nums[l] + nums[r];
if(target == sum){
res.add(Arrays.asList(nums[i], nums[l], nums[r]));
l++;
r--;
} else if (sum < target) {
l++;
} else {
r--;
}
}
}
return res;
}
}
但是还要去重:
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
for(int i = 0; i < nums.length; i ++){
if (i > 0 && nums[i] == nums[i - 1]) continue; // 外层去重
int l = i + 1;
int r = nums.length - 1;
int target = -nums[i];
while(l < r){
int sum = nums[l] + nums[r];
if(target == sum){
res.add(Arrays.asList(nums[i], nums[l], nums[r]));
while(l < r && nums[l] == nums[l + 1]) l++;
while(l < r && nums[r] == nums[r - 1]) r--;
l++;
r--;
} else if (sum < target) {
l++;
} else {
r--;
}
}
}
return res;
}
}
42. 接雨水 - 力扣(LeetCode)
这一题是盛水容器的高级版本,建议下一次遇到还是用双指针做,动态规划需要维护正向遍历和反向遍历两个数组,短时间内是想不出来的。
首先我们要记住,我们需要分别向左向右遍历。
对于单向的遍历,那向左遍历举例,我们假设右边有一个很高的柱子能把水留住,那么能接住多少水只取决于左边的最大值。 res = res + (l_max - l); 右边同理。
我们就两边的l r指针各自遍历,直到他们遇到。因为取决于的是更小的柱子,跟盛水不一样,盛水取决于高的柱子。所以就相当于在l和r遇到的地方有一个很高的柱子,但是它不会比l_max和r_max小。因为我们是移动l和r里更矮的指针,他们最后会在接雨水最高的的地方重合。
class Solution {
public int trap(int[] height) {
int l = 0;
int r = height.length - 1;
int left_max = 0, right_max = 0;
int result = 0;
while(l < r){
//移动较矮一侧的指针
if(height[l] < height[r]){
if(left_max < height[l]){
left_max = height[l];
} else{
result = result + (left_max - height[l]);//我们假设右边有一个很高的柱子
}
l++;
} else{
if(right_max < height[r]){
right_max = height[r];
} else{
result = result + (right_max - height[r]);//我们假设右边有一个很高的柱子
}
r--;
}
}
return result;
}
}