5.8 二轮 哈希+区间

This commit is contained in:
zhangsan 2025-05-08 11:05:42 +08:00
parent 7518637900
commit 60f7c9d91f
10 changed files with 389 additions and 0 deletions

View File

@ -0,0 +1,33 @@
package hash;
/**
* 题目 383. 赎金信 (canConstruct)
* 描述给你两个字符串ransomNote magazine 判断 ransomNote 能不能由 magazine 里面的字符构成
*
* 如果可以返回 true 否则返回 false
*
* magazine 中的每个字符只能在 ransomNote 中使用一次
*
* 示例 1
输入ransomNote = "a", magazine = "b"
输出false
* 链接https://leetcode.cn/problems/ransom-note/
*/
public class CanConstruct {
public boolean canConstruct(String ransomNote, String magazine) {
if (ransomNote.length() > magazine.length()) {
return false;
}
int[] cnt = new int[26];
for (char c : magazine.toCharArray()) {
cnt[c - 'a']++;
}
for (char c : ransomNote.toCharArray()) {
cnt[c - 'a']--;
if(cnt[c - 'a'] < 0) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,30 @@
package hash;
import java.util.HashMap;
import java.util.Map;
/**
* 题目 219. 存在重复元素 II (containsNearbyDuplicate)
* 描述给你一个整数数组 nums 和一个整数 k 判断数组中是否存在两个 不同的索引 i j 满足 nums[i] == nums[j] abs(i - j) <= k 如果存在返回 true 否则返回 false
*
*
* 示例 1
输入nums = [1,2,3,1], k = 3
输出true
* 链接https://leetcode.cn/problems/contains-duplicate-ii/
*/
public class ContainsNearbyDuplicate {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer>map=new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if(map.containsKey(nums[i])){
if(i-map.get(nums[i])<=k)
return true;
else map.put(nums[i],i);
}else
map.put(nums[i],i);
}
return false;
}
}

View File

@ -0,0 +1,27 @@
package hash;
/**
* 题目 242. 有效的字母异位词 (isAnagram)
* 描述给定两个字符串 s t 编写一个函数来判断 t 是否是 s 字母异位词
*字母异位词是通过重新排列不同单词或短语的字母而形成的单词或短语并使用所有原字母一次
*
* 示例 1
输入: s = "anagram", t = "nagaram"
输出: true
* 链接https://leetcode.cn/problems/valid-anagram/
*/
public class IsAnagram {
public boolean isAnagram(String s, String t) {
if(s.length() != t.length())
return false;
int[] alpha = new int[26];
for(int i = 0; i< s.length(); i++) {
alpha[s.charAt(i) - 'a'] ++;
alpha[t.charAt(i) - 'a'] --;
}
for(int i=0;i<26;i++)
if(alpha[i] != 0)
return false;
return true;
}
}

View File

@ -0,0 +1,48 @@
package hash;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
/**
* 题目 202. 快乐数 (IsHappy)
* 描述编写一个算法来判断一个数 n 是不是快乐数
*
* 快乐数 定义为
*
* 对于一个正整数每一次将该数替换为它每个位置上的数字的平方和
* 然后重复这个过程直到这个数变为 1也可能是 无限循环 但始终变不到 1
* 如果这个过程 结果为 1那么这个数就是快乐数
* 如果 n 快乐数 就返回 true 不是则返回 false
*
* 示例 1
输入n = 19
输出true
解释
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
* 链接https://leetcode.cn/problems/happy-number/
*/
public class IsHappy {
private int next(int n) {
int sum = 0;
while (n > 0) {
int digit = n % 10;
sum += digit * digit;
n /= 10;
}
return sum;
}
public boolean isHappy(int n) {
Set<Integer> seen = new HashSet<>();
while (n != 1 && !seen.contains(n)) {
seen.add(n);
n = next(n);
}
return n == 1;
}
}

View File

@ -0,0 +1,65 @@
package hash;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 题目 205. 同构字符串 (isIsomorphic
* 描述给定两个字符串 s t 判断它们是否是同构的
* 如果 s 中的字符可以按某种映射关系替换得到 t 那么这两个字符串是同构的
* 每个出现的字符都应当映射到另一个字符同时不改变字符的顺序不同字符不能映射到同一个字符上相同字符只能映射到同一个字符上字符可以映射到自己本身
*
* 示例 1
输入s = "egg", t = "add"
输出true
* 链接https://leetcode.cn/problems/isomorphic-strings/
*/
public class IsIsomorphic {
public boolean isIsomorphic(String s, String t) {
int cnt=s.length();
if(cnt!=t.length())
return false;
Map<Character,Character>map1=new HashMap<>();
Map<Character,Character>map2=new HashMap<>();
for (int i = 0; i < cnt; i++) {
char curs=s.charAt(i),curt=t.charAt(i);
if(!map1.containsKey(curs)&&!map2.containsKey(curt)) {
map1.put(curs, curt);
map2.put(curt,curs);
}
else if(!map1.containsKey(curs)&&map2.containsKey(curt)||map1.containsKey(curs)&&!map2.containsKey(curt))
return false;
else{
if(!map1.get(curs).equals(curt))
return false;
}
}
return true;
}
public boolean isIsomorphic2(String s, String t) {
int n = s.length();
if (n != t.length()) return false;
Map<Character, Character> map = new HashMap<>(n);
Set<Character> used = new HashSet<>(n);
for (int i = 0; i < n; i++) {
char cs = s.charAt(i), ct = t.charAt(i);
if (map.containsKey(cs)) {
// 已有映射检查一致性
if (map.get(cs) != ct) return false;
} else {
// 新的映射确保 ct 还没被用过
if (used.contains(ct)) return false;
map.put(cs, ct);
used.add(ct);
}
}
return true;
}
}

View File

@ -0,0 +1,39 @@
package hash;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* 题目 290. 单词规律 (wordPattern)
* 描述给定一种规律 pattern 和一个字符串 s 判断 s 是否遵循相同的规律
*
* 这里的 遵循 指完全匹配例如 pattern 里的每个字母和字符串 s 中的每个非空单词之间存在着双向连接的对应规律
*
* 示例 1
输入: pattern = "abba", s = "dog cat cat dog"
输出: true
* 链接https://leetcode.cn/problems/word-pattern/
*/
public class WordPattern {
public boolean wordPattern(String pattern, String s) {
String[] res=s.split("\\s");
if(res.length!=pattern.length())
return false;
Map<Character,String> map=new HashMap<>();
Set<String>set=new HashSet<>();
for (int i = 0; i < pattern.length(); i++) {
char cur=pattern.charAt(i);
if(map.containsKey(cur)) {
if(!map.get(cur).equals(res[i])) return false;
}else{
if(set.contains(res[i]))return false;
map.put(cur,res[i]);
set.add(res[i]);
}
}
return true;
}
}

View File

@ -0,0 +1,49 @@
package range;
import java.util.ArrayList;
import java.util.List;
/**
* 题目 57. 插入区间 (insert)
* 描述给你一个 无重叠的 按照区间起始端点排序的区间列表 intervals其中 intervals[i] = [starti, endi] 表示第 i 个区间的开始和结束并且 intervals 按照 starti 升序排列同样给定一个区间 newInterval = [start, end] 表示另一个区间的开始和结束
* intervals 中插入区间 newInterval使得 intervals 依然按照 starti 升序排列且区间之间不重叠如果有必要的话可以合并区间
* 返回插入之后的 intervals
* 注意 你不需要原地修改 intervals你可以创建一个新数组然后返回它
*
* 示例 1
输入intervals = [[1,3],[6,9]], newInterval = [2,5]
输出[[1,5],[6,9]]
* 链接https://leetcode.cn/problems/insert-interval/
*/
//想起来有点复杂
public class Insert {
public int[][] insert(int[][] intervals, int[] newInterval) {
List<int[]> res = new ArrayList<>();
int i = 0, n = intervals.length;
// 第一阶段添加所有在 newInterval 左侧且不重叠的区间
while (i < n && intervals[i][1] < newInterval[0]) {
res.add(intervals[i]);
i++;
}
// 第二阶段 newInterval 重叠的区间合并到 newInterval
while (i < n && intervals[i][0] <= newInterval[1]) {
newInterval[0] = Math.min(newInterval[0], intervals[i][0]);
newInterval[1] = Math.max(newInterval[1], intervals[i][1]);
i++;
}
// 把合并后的 newInterval 加进去
res.add(newInterval);
// 第三阶段添加所有在 newInterval 右侧且不重叠的区间
while (i < n) {
res.add(intervals[i]);
i++;
}
// 转回二维数组并返回
return res.toArray(new int[res.size()][]);
}
}

View File

@ -0,0 +1,60 @@
package range;
import java.util.ArrayList;
import java.util.List;
/**
* 题目228. 汇总区间 (summaryRanges)
* 描述给定一个 无重复元素 有序 整数数组 nums
*
* 返回 恰好覆盖数组中所有数字 最小有序 区间范围列表 也就是说nums 的每个元素都恰好被某个区间范围所覆盖并且不存在属于某个范围但不属于 nums 的数字 x
*
* 列表中的每个区间范围 [a,b] 应该按如下格式输出
*
* "a->b" 如果 a != b
* "a" 如果 a == b
*
* 链接https://leetcode.cn/problems/summary-ranges/
*
示例 1
输入nums = [0,1,2,4,5,7]
输出["0->2","4->5","7"]
解释区间范围是
[0,2] --> "0->2"
[4,5] --> "4->5"
[7,7] --> "7"
*/
public class SummaryRanges {
public List<String> summaryRanges(int[] nums) {
List<String> ranges = new ArrayList<>();
if (nums == null || nums.length == 0) {
return ranges;
}
int start = nums[0], end = nums[0];
StringBuilder sb = new StringBuilder();
for (int i = 1; i < nums.length; i++) {
if (nums[i] == end + 1) {
end = nums[i];
} else {
sb.append(start);
if (start != end) {
sb.append("->").append(end);
}
ranges.add(sb.toString());
sb.setLength(0);
start = end = nums[i];
}
}
sb.append(start);
if (start != end) {
sb.append("->").append(end);
}
ranges.add(sb.toString());
return ranges;
}
}

View File

@ -0,0 +1,22 @@
package hash;
import org.junit.Test;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import static org.junit.Assert.*;
public class IsHappyTest {
@Test
public void isHappy() {
int n = 19;
IsHappy solution = new IsHappy();
boolean res=solution.isHappy(n);
if(res)
System.out.println("yes");
else System.out.println("no");
}
}

View File

@ -0,0 +1,16 @@
package hash;
import org.junit.Test;
import static org.junit.Assert.*;
public class IsIsomorphicTest {
@Test
public void isIsomorphic() {
String s = "egg", t = "add";
IsIsomorphic solution = new IsIsomorphic();
solution.isIsomorphic(s,t);
}
}