1153 String Transforms Into Another String 字符串轉化
描述
給出兩個長度相同的字符串,分別是 str1
和 str2
。請你幫忙判斷字符串 str1 能不能在 零次
或 多次
轉化后變成字符串 str2。
每一次轉化時,將會一次性將 str1 中出現的 所有
相同字母變成其他 任何
小寫英文字母(見示例)。
只有在字符串 str1 能夠通過上述方式順利轉化為字符串 str2 時才能返回 True,否則返回 False。
- 示例 1:
輸入:str1 = "aabcc", str2 = "ccdee"
輸出:true
解釋:將 'c' 變成 'e',然后把 'b' 變成 'd',接着再把 'a' 變成 'c'。注意,轉化的順序也很重要。
- 示例 2:
輸入:str1 = "leetcode", str2 = "codeleet"
輸出:false
解釋:我們沒有辦法能夠把 str1 轉化為 str2。
- 提示:
1 <= str1.length == str2.length <= 10^4
str1 和 str2 中都只會出現 小寫英文字母
思路
轉化
的定義: 一次性將字符串中出現的 所有
相同字母
變成其他 任何
小寫英文字母
例如:aabcc --> ccbcc(a轉化成c) --> eebee(c轉化成e)
由上圖可以看出:
轉化的真正意義是 多對一映射 如此可以得出以下判斷依據:
-
判斷依據一: 字符種類
轉化后的字符種類必定小於或者剛好等於轉化前的字符種類
注意:這種映射是有限制的, 它只能轉化成小寫字母
, 即它只能在26個小寫字母之間轉化,
所以目標字符串的字符種類不能為26(滿值), 除非兩字符串相等, 否則必定無法轉化 -
判斷依據二: 映射表
可以建立映射表, 查看是否為多對一的映射
代碼實現
- 使用兩個HashMap來構建映射表
使用兩個HashMap來構建映射表
class Solution {
public boolean canConvert(String str1, String str2) {
if (null == str1 | null == str2) return false;
// 兩字符串長度不一必定無法轉化
if (str1.length() != str2.length()) return false;
// 兩字符串相等 無需轉化
if (str1.equals(str2)) return true;
// 求元素種類
HashSet<Character> set = new HashSet<>();
for (char c : str1.toCharArray()) set.add(c);
int size1 = set.size();
set.clear();
for (char c : str2.toCharArray()) set.add(c);
int size2 = set.size();
// 轉換字符串str2元素種類滿26 必定無法轉化
// 轉化后字符串元素種類比轉化前還多
if (size2 == 26 | size1 < size2) return false;
// 建立映射表
// str1ToStr2 存放被轉化字符串的字符及其轉化后字符所對應的標識label 字符 -> label 多對一
HashMap<Character, Integer> str1ToStr2 = new HashMap<>();
// str2Table 存放轉化后字符所對應的標識label 字符 -> label 一對一
HashMap<Character, Integer> str2Table = new HashMap<>();
// label 轉化后字符所對應的標識label
int label = 0;
// 遍歷字符
char c1, c2;
for (int i = 0; i < str1.length(); i++) {
c1 = str1.charAt(i);
c2 = str2.charAt(i);
// c1 --> c2
// c2沒有被標識
if (!str2Table.containsKey(c2)) {
// c1已經有轉化對應字符了 c1!->c2 多對多
if (str1ToStr2.containsKey(c1)) return false;
// c1 -> label
str1ToStr2.put(c1, label);
// c2 -> label
str2Table.put(c2, label);
label++;
}
// c2已經被標識 c1沒有被標識(還沒有確定轉化字符)
if (!str1ToStr2.containsKey(c1)) {
// c1 -> label -> c2
str1ToStr2.put(c1, str2Table.get(c2));
}
// c1,c2都已經被標識 查看兩者標識是否相同
// c1 -> label ?-> c2
if (str1ToStr2.get(c1) != str2Table.get(c2)) {
return false;
}
}
return true;
}
}
- 使用數組來構建映射表
使用數組來構建映射表
class Solution {
public boolean canConvert(String str1, String str2) {
if (null == str1 | null == str2) return false;
// 兩字符串長度不一必定無法轉化
if (str1.length() != str2.length()) return false;
// 兩字符串相等 無需轉化
if (str1.equals(str2)) return true;
// 求元素種類
int n = str1.length(), size1 = 0, size2 = 0, p = 0, q = 0;
boolean[] v1 = new boolean[30];
boolean[] v2 = new boolean[30];
for (int i = 0; i < n; i++) {
p = str1.charAt(i) - 'a';
q = str2.charAt(i) - 'a';
if (!v1[p]) {
size1++;
v1[p]=true;
}
if (!v2[q]) {
size2++;
v2[q]=true;
}
}
// 轉換字符串str2元素種類滿26 必定無法轉化
// 轉化后字符串元素種類比轉化前還多
if (size2 == 26 | size1 < size2) return false;
// 建立映射表
// s1ToS2 映射表 下標表示原字符-'a' 值表示目標字符
char[] s1ToS2 = new char[30];
char c = '#';
// 映射表初始化為全'#'
for (int i = 0; i < 26; i++) s1ToS2[i] = '#';
for (int i = 0; i < n; i++) {
p = str1.charAt(i) - 'a';
c = str2.charAt(i);
// 該字符p還沒有映射
// 或者
// 該字符p映射已經映射 且映射單一
if (s1ToS2[p] == '#' | s1ToS2[p] == c) s1ToS2[p]=c;
else return false;
}
return true;
}
}