383.赎金信
简单
给你两个字符串:ransomNote
和 magazine
,判断 ransomNote
能不能由 magazine
里面的字符构成。
如果可以,返回 true
;否则返回 false
。
magazine
中的每个字符只能在 ransomNote
中使用一次。
示例 1:
输入:ransomNote = "a", magazine = "b" 输出:false
示例 2:
输入:ransomNote = "aa", magazine = "ab" 输出:false
示例 3:
输入:ransomNote = "aa", magazine = "aab" 输出:true
提示:
1 <= ransomNote.length, magazine.length <= 105
ransomNote
和magazine
由小写英文字母组成
class Solution {
// 判断ransomNote字符串是否可以由magazine字符串构造
public boolean canConstruct(String ransomNote, String magazine) {
// 创建一个HashMap用于存储magazine字符串中每个字符出现的次数
Map<Character,Integer> map = new HashMap<>();
for(int i = 0; i < magazine.length(); i++){
char temp = magazine.charAt(i);
// 如果map中已经存在该字符,则将其对应的值加1;否则,将该字符添加到map中,并将其值设为1
map.put(temp,map.getOrDefault(temp,0) + 1);
}
// 遍历ransomNote字符串中的每个字符
for(int i = 0; i < ransomNote.length(); i++){
char temp = ransomNote.charAt(i);
// 如果map中不存在该字符,说明ransomNote无法由magazine构造,返回false
if(!map.containsKey(temp)){
return false;
}
// 如果map中该字符的值大于1,说明ransomNote中还有该字符未匹配,将其值减1
if(map.get(temp) > 1){
map.put(temp,map.get(temp) - 1);
}else{
// 如果map中该字符的值等于1,说明ransomNote中所有该字符都已匹配,将其从map中移除
map.remove(temp);
}
}
// 如果ransomNote中的所有字符都能在magazine中找到匹配,返回true
return true;
}
}
关于字符串的哈希题目还是用数组作为哈希表运行时间小一些
class Solution {
public boolean canConstruct(String ransomNote, String magazine) {
// shortcut
if (ransomNote.length() > magazine.length()) {
return false;
}
// 定义一个哈希映射数组
int[] record = new int[26];
// 遍历
for(char c : magazine.toCharArray()){
record[c - 'a'] += 1;
}
for(char c : ransomNote.toCharArray()){
record[c - 'a'] -= 1;
}
// 如果数组中存在负数,说明ransomNote字符串总存在magazine中没有的字符
for(int i : record){
if(i < 0){
return false;
}
}
return true;
}
}
双向映射
205.同构字符串
简单
给定两个字符串 s
和 t
,判断它们是否是同构的。
如果 s
中的字符可以按某种映射关系替换得到 t
,那么这两个字符串是同构的。
每个出现的字符都应当映射到另一个字符,同时不改变字符的顺序。不同字符不能映射到同一个字符上,相同字符只能映射到同一个字符上,字符可以映射到自己本身。
示例 1:
输入:s ="egg"
, t ="add"
输出:true
示例 2:
输入:s ="foo"
, t ="bar"
输出:false
示例 3:
输入:s ="paper"
, t ="title"
输出:true
提示:
1 <= s.length <= 5 * 104
t.length == s.length
s
和t
由任意有效的 ASCII 字符组成
需要我们判断 s 和 t每个位置上的字符是否都一一对应,即 s 的任意一个字符被 t中唯一的字符对应,同时 t的任意一个字符被 s中唯一的字符对应。这也被称为「双射」的关系。
以示例 2 为例,t中的字符 a和 r 虽然有唯一的映射 o,但对于 s中的字符 o 来说其存在两个映射 {o,a},{o,r},故不满足条件。
因此,我们维护两张哈希表,第一张哈希表以 s 中字符为键,映射至 t 的字符为值,第二张哈希表以 t 中字符为键,映射至 s 的字符为值。从左至右遍历两个字符串的字符,不断更新两张哈希表,如果出现冲突,即sMap 中已经包含当前字符 sArr[i] 并且映射关系不匹配,或者 tMap 中已经包含当前字符 tArr[i] 并且映射关系不匹配,返回false。
如果遍历结束没有出现冲突,则表明两个字符串是同构的,返回 true即可。
import java.util.*;
class Solution {
public boolean isIsomorphic(String s, String t) {
// 使用两个哈希映射来存储 s 到 t 和 t 到 s 的映射关系
Map<Character, Character> sMap = new HashMap<Character, Character>(); // 存储 s 到 t 的映射关系
Map<Character, Character> tMap = new HashMap<Character, Character>(); // 存储 t 到 s 的映射关系
char[] sArr = s.toCharArray(); // 将字符串 s 转换为字符数组
char[] tArr = t.toCharArray(); // 将字符串 t 转换为字符数组
// 遍历字符串的字符数组
for (int i = 0; i < sArr.length; ++i) {
// 如果 sMap 中已经包含当前字符 sArr[i] 并且映射关系不匹配,或者 tMap 中已经包含当前字符 tArr[i] 并且映射关系不匹配
if ((sMap.containsKey(sArr[i]) && sMap.get(sArr[i]) != tArr[i]) || (tMap.containsKey(tArr[i]) && tMap.get(tArr[i]) != sArr[i])) {
// 则返回 false,因为不满足同构的条件
return false;
}
// 将字符 sArr[i] 到 tArr[i] 的映射关系存储到 sMap 中
sMap.put(sArr[i], tArr[i]);
// 将字符 tArr[i] 到 sArr[i] 的映射关系存储到 tMap 中
tMap.put(tArr[i], sArr[i]);
}
// 如果遍历结束都没有返回 false,则说明 s 和 t 是同构的,返回 true
return true;
}
}
290.单词规律
简单
给定一种规律 pattern
和一个字符串 s
,判断 s
是否遵循相同的规律。
这里的 遵循 指完全匹配,例如, pattern
里的每个字母和字符串 s
中的每个非空单词之间存在着双向连接的对应规律。
示例1:
输入: pattern ="abba"
, s ="dog cat cat dog"
输出: true
示例 2:
输入:pattern ="abba"
, s ="dog cat cat fish"
输出: false
示例 3:
输入: pattern ="aaaa"
, s ="dog cat cat dog"
输出: false
提示:
1 <= pattern.length <= 300
pattern
只包含小写英文字母1 <= s.length <= 3000
s
只包含小写英文字母和' '
s
不包含 任何前导或尾随对空格s
中每个单词都被 单个空格 分隔
这道题和上一道题是一个思路
import java.util.HashMap;
import java.util.Map;
class Solution {
public boolean wordPattern(String pattern, String s) {
// 创建两个哈希映射,一个用于将字符映射到字符串,另一个用于将字符串映射到字符
Map<Character,String> patternMap = new HashMap<>();
Map<String,Character> sMap = new HashMap<>();
// 将模式字符串和目标字符串分割成字符数组和单词数组
char[] patternArr = pattern.toCharArray();
String[] sArr = s.split(" ");
// 检查模式和字符串的长度是否相同
if(sArr.length != patternArr.length){
return false;
}
// 遍历模式字符串和单词数组
for(int i = 0; i < patternArr.length; i++){
// 如果模式字符已经在映射中,但对应的字符串不同,或者字符串已经在映射中,但对应的模式字符不同,则返回false
if((patternMap.containsKey(patternArr[i]) && !patternMap.get(patternArr[i]).equals(sArr[i])) ||(sMap.containsKey(sArr[i]) && !sMap.get(sArr[i]).equals(patternArr[i]))){
return false;
}
// 将当前模式字符和字符串加入到映射中
patternMap.put(patternArr[i],sArr[i]);
sMap.put(sArr[i],patternArr[i]);
}
// 如果遍历结束没有返回false,则返回true
return true;
}
}