文章目录
- 面试经典150题【41-50】
- 49.字母异位词分组
- 1. 两数之和
- 202.快乐数
- 219. 存在重复元素II
- 128.最长连续序列
- 228. 汇总区间
- 56.合并区间(华为面试题)
- 57.插入区间
- 452.用最少的箭引爆气球
- 20.有效的括号
面试经典150题【41-50】
49.字母异位词分组
用这种流式的处理
return new ArrayList<>(Arrays.stream(strs).collect(Collectors.groupingBy(str -> { 处理逻辑 })).values() );
不然处理起来太麻烦了。
class Solution {public List<List<String>> groupAnagrams(String[] strs) {return new ArrayList<>(Arrays.stream(strs).collect(Collectors.groupingBy(str -> {// 返回 str 排序后的结果。// 按排序后的结果来grouping by,算子类似于 sql 里的 group by。char[] array = str.toCharArray();Arrays.sort(array);return new String(array);})).values());}
}
如果不排序的话,可以进行编码: [b,a,a,a,b,c] 编码成 a3b2c1, 然后再group by.
class Solution {public List<List<String>> groupAnagrams(String[] strs) {return new ArrayList<>(Arrays.stream(strs).collect(Collectors.groupingBy(str -> {int[] counter = new int[26];for (int i = 0; i < str.length(); i++) {counter[str.charAt(i) - 'a']++;}StringBuilder sb = new StringBuilder();for (int i = 0; i < 26; i++) {// 这里的 if 是可省略的,但是加上 if 以后,生成的 sb 更短,后续 groupingBy 会更快。if (counter[i] != 0) {sb.append((char) ('a' + i));sb.append(counter[i]);}}return sb.toString();})).values());}
}
1. 两数之和
每遍历一个数,就把这个数字放到哈希表里。当遍历到下一个数字的时候,看哈希表里是否存在Key为 target - nums[i] 的值。
202.快乐数
这个如果不是1,会进入一个循环。判断循环就用双指针就行。
判断成环。一个是可以用快慢指针,他们俩相遇则有环。一个是可以用一个set,如果有重复元素则有环。
219. 存在重复元素II
区间大小为k,但是怎么保证K个里面能直接查出元素呢。
方法一:定义一个大小为k的hashSet, 如果包含元素则说明重复。因为hashSet会自动扩容,所以写法是: if(hashSet.size() > k) hashSet.remove(nums[ i -k ] )
方法二:哈希表记录[k,v]—> [ nums[i],i] ,如果包含则比较与i的距离,大于k则将[nums[i],j] 赋值给[nums[i],i] ,继续遍历。
128.最长连续序列
因为是O(n) ,所以不能排序。遍历一遍,放到set里。
然后再遍历一遍Set, 如果包含 nums[i]+1,依次遍历有没有nums[i] +2, nums[i] +3 等等
但是这样也会导致很多重复的遍历。 可以放到map里 [key,value] ->[ nums[i], 左右最长的长度]
当前的长度 = left + right +1
public int longestConsecutive(int[] nums) {HashMap<Integer,Integer> hashMap=new HashMap<>();int ans=0;for(int i=0;i<nums.length;i++){//包含说明以前处理过,不包含的话可能是单独,也可能是边界,也可能是刚好插在俩个大条之间if(!hashMap.containsKey(nums[i])){int left=hashMap.getOrDefault(nums[i]-1,0);int right=hashMap.getOrDefault(nums[i]+1,0);int tempAns=left+right+1;if(tempAns>ans){ans=tempAns;}hashMap.put(nums[i],tempAns);//不能只更新自己,边界也要更新hashMap.put(nums[i]+right,tempAns);hashMap.put(nums[i]-left,tempAns);}}return ans;}
228. 汇总区间
按照题意模拟即可。
56.合并区间(华为面试题)
先按左区间排序,然后依次遍历,根据 nums[i+1][0] 和 nums[i][1] 判断是否需要合并。
public class LC56 {public int[][] merge(int[][] intervals) {Arrays.sort(intervals, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {return o1[0]-o2[0];}});ArrayList<int[]> ans=new ArrayList<>();int left=intervals[0][0],right=intervals[0][1];for(int i=1;i<intervals.length;i++){if(intervals[i][0]>right){//不合并,装载ans.add(new int[]{left,right});//开始记录新的区间left=intervals[i][0];right=intervals[i][1];}else{//合并区间right=Math.max(right,intervals[i][1]);}}//无论是intervals里只有一个元素的特判, 还是 正常情况下最后一步, 都要有下面这一行。ans.add(new int[]{left,right});return ans.toArray(new int[][]{});}
}
57.插入区间
和56.合并区间一个意思
452.用最少的箭引爆气球
所有的这种二维数组的,都要先排序。无非就是按照 左边界 排序 或者按照 右边界 排序。
而气球这种场景,应该是按照右边界排序,然后射击第一个存在的气球的最右边。
判断此次射击会爆几个气球,要看别的气球的左边界是否小于射击点。(因为是按右边界排序的,右边肯定是大的,左边小就能被射到)
public int findMinArrowShots(int[][] points) {if(points.length==0) return 0;Arrays.sort(points, new Comparator<int[]>() {@Overridepublic int compare(int[] o1, int[] o2) {//return o1[1]-o2[1];if(o1[1]>o2[1]){return 1;}else if(o1[1]<o2[1]){return -1;}else{return 0;}}});//按右边界 进行排序//击毙第一个气球的最右边,能击毙几个算几个。//pos为击毙点int pos=points[0][1];int ans=1;for(int i=0;i<points.length;i++){//因为是按右边界排序的,判断第i个气球爆没爆,要看第i个气球的左边界。if(pos<points[i][0]){ans++;pos=points[i][1];}}return ans;}
20.有效的括号
一个个单词放到栈里,放左括号,遇到右括号检查栈顶是否为对应的左括号即可。