128. 最长连续序列
不要求在位置数组中是连续的
输入:nums = [100,4,200,1,3,2]
输出:4
解释:最长数字连续序列是 [1, 2, 3, 4]。它的长度为 4。
两种最朴素的解法之一:
- 先排序,从前往后找最长连续上升序列即可。该思路简单有效,但是复杂度已经至少有 O(nlogn)。实现起来也比较简单,在此不讨论该解法。
- 遍历数组中的每个元素num,然后以num为起点,每次+1向后遍历num+1,num+2,num+3...,判断这些元素是否存在于数组中。假设找到的最大的连续存在的元素为num+x,那么这个连续序列的长度即为x+1。最后将每个num所开始序列长度取个最大值即可。
解题思路1:哈希集合
上面的代码不用想,是肯定超时的。它的最坏时间复杂度已经达到了 O(n^3)
我们需要优化代码。优化的点主要有两个:
- 判断num+1,num+2,num+3...是否在数组中。上面的代码是用直接遍历的方式去查找的,时间复杂度为 O(n) 。我们可以改为哈希表查找,时间复杂度为 O(1)
- 遍历数组中每个元素num。逐一遍历每个元素会产生很多冗余工作,实际上我们无需一次针对每个元素num去判断num+1,num+2,num+3...是否在数组中。如果num-1已经在数组中的话,那么num-1肯定会进行相应的+1遍历,然后遍历到num,而且从num-1开始的+1遍历必定比从num开始的+1遍历得到的序列长度更长。因此,我们便可将在一个连续序列中的元素进行删减,让其只在最小的元素才开始+1遍历。比如,现有元素[1,2,4,3,5],当2,3,4,5发现均有比自己小1的元素存在,那么它们就不会开始+1遍历,而1是连续序列中最小的元素,没有比自己小1的元素存在,所以会开始+1遍历。通过上述方式便可将时间复杂度优化至O(n)。
class Solution { //哈希表实现。哈希表的 插入、删除、查找的时间复杂度近似为 O(1) 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.add(nums[i]); } int ans = 1; for (int num:set) { int cur = num; // 如果 num-1 存在,那么 num 就不用搜索了,搜索 num-1 的时候一直往后 +1 搜索会把 num 包括进去 // 当 num-1 不存在,才开始往后搜索 if (!set.contains(num-1)) { // 只有当num-1不存在时,才开始向后遍历num+1,num+2,num+3...... while (set.contains(cur+1)) { cur++; } // [num, cur] 是连续的区间 ans = Math.max(ans, cur-num+1); } } return ans; } // 这样复杂度取决于排序的复杂度 public int longestConsecutive2(int[] nums) { if (nums.length == 0) { return 0; } // 排序 Arrays.sort(nums); int longestLen = 1; int curLen = 1; for (int i=0;i<nums.length;i++) { if (i > 0) { // 0 1 1 1 2 这种,前面重复的1都跳过跳过 if (nums[i] == nums[i-1]) { continue; } // 0 1 1 1 2 这种,到 2 的时候,不能和前一个 1 比较,要一直跳到第一个 1 去比较 int lastDiffIndex = i-1; while (lastDiffIndex > 0 && nums[lastDiffIndex] == nums[lastDiffIndex-1]) { lastDiffIndex-=1; } // 已排序,与前一个的差值为 1 则说明是连续的 if (nums[i] - nums[lastDiffIndex] == 1) { longestLen = Math.max(longestLen, curLen+=1); } else { // 不连续了,curLen 重新开始计算 curLen = 1; } } } return longestLen; } }
49. 字母异位词分组

字母异位的词排序之后都是一样的
所以对每个字符串先排序
排序后的字符串作为 HashMap 的 key
而 value 则是字母异位词的 List
注意对字符串排序的方法是
char[] orderStrArr = str.toCharArray(); Arrays.sort(orderStrArr); String orderStr = String.valueOf(orderStrArr);
class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, List<String>> orderStr2StrListMap = new HashMap(); for (String str : strs) { char[] orderStrArr = str.toCharArray(); Arrays.sort(orderStrArr); String orderStr = String.valueOf(orderStrArr); List<String> strList = orderStr2StrListMap.get(orderStr); if (strList == null) { strList = new ArrayList(); orderStr2StrListMap.put(orderStr, strList); } strList.add(str); } List<List<String>> res = new ArrayList(); for(Map.Entry<String, List<String>> entry : orderStr2StrListMap.entrySet()) { res.add(entry.getValue()); } return res; } }