- 刷题日记 - 6
- 205. 同构字符串 - 力扣(LeetCode)
- 290. 单词规律 - 力扣(LeetCode)
- 242. 有效的字母异位词 - 力扣(LeetCode)
- 202. 快乐数 - 力扣(LeetCode)
- 219. 存在重复元素 II - 力扣(LeetCode)
- 228. 汇总区间 - 力扣(LeetCode)
- 57. 插入区间 - 力扣(LeetCode)
刷题日记 - 6
难度:简单
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Solution { public boolean isIsomorphic(String s, String t) { int sLen = s.length(); int tLen = t.length(); if(sLen != tLen) return false; if(sLen < 1) return true;
char[] sChars = s.toCharArray(); char[] tChars = t.toCharArray();
int[] map = new int[128]; int[] charStatus = new int[128]; Arrays.fill(map, -1);
boolean res = true; for (int i = 0; i < sLen; i++) { char s_ = sChars[i]; char t_ = tChars[i];
if (map[s_] == -1 && charStatus[t_] == 0) { map[s_] = t_; charStatus[t_] = 1; } else { if (map[s_] == -1 || map[s_] != t_) { res = false; break; } } } return res; } }
|
因为输入的字符属于ascii字符,数量不多且范围确定,可以用数组模拟哈希表。
值得注意的是:不同字符不能映射到同一个字符上,所以需要一个新的charStatus[]来记录当前字符被是否被映射了。
对于当前字符s_和t_
- 如果发现
s_没有映射,t_没有被映射,那么就更新映射关系,标记t_已经被映射了
- 如果发现
s_没有映射,t_却被映射了,那可以直接退出了,因为t_那个肯定不是被s_映射的,出现了多个字符映射到一个字符的情况,False
- 如果发现
s_有映射,t_也被映射了,就直接判断当前s_映射的是不是t_即可。
- 如果发现
s_有映射了,t_没有被映射 。。。。。。。(这是不可能会出现的情况)
难度:简单
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Solution { public boolean wordPattern(String pattern, String s) { String[] words = s.split(" "); int len = words.length;
if (len != pattern.length()) return false;
HashMap<Character, String> map = new HashMap<>(); HashSet<String> set = new HashSet<>(); char[] patternChars = pattern.toCharArray();
for (int i = 0; i < len; i++) { char cur = patternChars[i]; String word = words[i];
if (!map.containsKey(cur) && !set.contains(word)) { map.put(cur, word); set.add(word); } else { if (!map.containsKey(cur) || !map.get(cur).equals(word)) { return false; } } }
return true; } }
|
同上一题,不过这一题不能再用数组模拟哈希表了。
难度:简单
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class Solution { public boolean isAnagram(String s, String t) { int len = s.length(); if(len!=t.length())return false;
int[] sCnt = new int[26]; int[] tCnt = new int[26];
for(char ch:s.toCharArray()){ sCnt[ch-'a']++; } for(char ch:t.toCharArray()){ tCnt[ch-'a']++; } boolean res = true; for(int i=0;i<26;i++){ if(sCnt[i]!=tCnt[i]){ res = false; break; } } return res; } }
|
因为s和t仅包含小写字母,那么范围是确定的,所以可以用数组模拟哈希表,记录每个字母的出现次数,最后比较两个数组即可。
进阶:如果输入字符串包含 Unicode 字符,范围不确定了,直接用哈希表即可。
Unicode字符和ASCII字符的区别主要在于字符集的大小、编码范围和表示的字符种类。
每个ASCII字符用1个字节(8位),实际只用了7位,0-127
Unicode 采用不同的编码方式,包括UTF-8(每个字符占用1到4个字节)、UTF-16(每个字符占用2或4个字节)和UTF-32(每个字符占用4个字节)
ASCII字符在UTF-8编码中是完全兼容的
难度:简单
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| class Solution { public boolean isHappy(int n) { HashSet<Integer> set = new HashSet<>(); set.add(n);
boolean res = true; while(n != 1) { int tmp = n; int sum = 0; int cur = -1; while(tmp > 0) { cur = tmp % 10; tmp /= 10; sum += cur * cur; } n = sum; if(set.contains(n)) { res = false; break; } set.add(n); } return res; } }
|
识别循环:用哈希表记录本轮的数字是否已经出现过,如果出现过就代表陷入循环。
难度:简单
哈希表
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { HashMap<Integer, Integer> map = new HashMap<>(); int len = nums.length; boolean res = false; for (int i = 0; i < len; i++) { int cur = nums[i]; if (!map.containsKey(cur)) { map.put(cur, i); } else { int lastCurIdx = map.get(cur); if (i - lastCurIdx <= k) { res = true; break; } map.put(cur, i); } } return res; } }
|
哈希表:Key存储数组中的值,Value存该值最新的索引。
索引差的判断:在找到重复元素后,需要检查它们的索引差(该元素目前最新与上一个最新)是否小于等于k。
难度:简单
区间题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| class Solution { public List<String> summaryRanges(int[] nums) {
int len = nums.length; List<String> res = new ArrayList<>(); if (len < 1) return res;
int start = nums[0]; int last = nums[0]; int p = 1;
while (p < len) { int cur = nums[p]; if (last + 1 == cur) { last = cur; } else { if (start == last) { res.add(String.valueOf(start)); } else { res.add(start + "->" + last); } start = cur; last = cur; } p++; }
if (start == last) { res.add(String.valueOf(start)); } else { res.add(start + "->" + last); } return res; } }
|
区间处理的逻辑理解和代码实现能力。
难度:中等
区间题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| class Solution { public int[][] insert(int[][] intervals, int[] newInterval) { List<int[]> res = new ArrayList<>(); int len = intervals.length; int p = 0; int left = newInterval[0]; int right = newInterval[1]; boolean flag = false;
while (p < len) { int[] interval = intervals[p]; if (interval[1] < left) { res.add(interval); } else if (interval[0] <= right) { left = Math.min(interval[0], left); right = Math.max(interval[1], right); } else if (interval[0] > right) { res.add(new int[]{left, right}); flag = true; break; } p++; }
while (p < len) { res.add(intervals[p]); p++; }
if (!flag) { res.add(new int[]{left, right}); }
return res.toArray(new int[res.size()][]); } }
|
处理重叠区间、边界条件
遍历所有原区间,相对于插入区间,有三种情况;
- 原区间在插入区间的左边
- 原区间有一部分在插入区间中
- 园区见在插入区间的右边
第一种和第三种情况都很简单,主要看第二种情况:计算两个交叉区间的等效区间,然后再将更新插入区间为等效区间,进行下一轮判断,直到找到下一个原区间满足第三种情况,这时候就直接可以将插入区间加入res了,包括这个在内的后面所有的原区间都可以直接加入res。但也有可能,插入区间就是最后一个区间,所以最后要判断一下插入区间是否被加入res了。