力扣-面試題刷題第一天
阿新 • • 發佈:2022-02-07
01.01. 判定字元是否唯一
01.02. 判定是否互為字元重排
01.01. 判定字元是否唯一
1、題目
實現一個演算法,確定一個字串 s 的所有字元是否全都不同。
2、初步作答
2.1 思路(錯誤)
作為從C轉過來的 java 選手,做題目第一時間想到的是利用兩重 for 迴圈判斷字串是否相同。
2.2 做法(錯誤)
使用 for 迴圈遍歷字串S(這裡把字串當成了陣列去操作,實操太少,自己太笨),再巢狀一層 for 迴圈遍歷S,遍歷過程中如果遇到相同字元,就返回 false ;迴圈結束,如果全部遍歷結束沒有返回 false ,那麼就返回 true 。
2.3 程式碼(錯誤)
錯誤解法
class Solution { public boolean isUnique(String astr) { if(astr == null){ return true; } for(int i = 0;i < s.length;i++){ for(int j = i+1;j < s.length;j++){ if(astr[i] == astr[j]){ return false; } } } return true; } }
- 這裡是錯誤思路的解法,當然就是錯誤解法啦。
2.4 思考
刷題經歷太少導致學過的資料結構演算法不知道該怎麼使用,只會簡單的迴圈結構疊加(弊端顯現啊,屬於是)。同時,字串不是陣列,這簡直就是語文當英語看,從頭錯到尾。
3、題目解析
3.1 思路說明
理解到自己的錯誤就去推翻之前的錯誤重新再來,那在這裡我們還需要多考慮幾種情況。
-
字串是否為空,空字串所有字元肯定全部不相同,直接返回 true;
-
字串中字元的範圍是什麼?
-
1.如果是26個英文字母,就有兩種情況需要討論
-
(1) 只能是小寫或大寫字母
- ① 字串長度大於26直接返回 false;
- ② 字串長度小於26時,定義一個大小為26的全0陣列。遍歷字串,以'a'=0~'z'=26或'A'=0~'Z'=26 為陣列下標,每個字元出現一次相應的陣列位加1,如果陣列中出現大於1的數時,返回false;如果遍歷結束之後,陣列所有元素都是0或1,則返回 true。
- 備註:這裡使用兩步判斷是為了節省運算時間和空間消耗,如果字串長度大於26,就不用開闢一個數組空間,同時節省了判斷的時間消耗。
-
(2) 大小寫字母都可以
- ① 字串長度大於52直接返回 false;
- ② 字串長度小於52時,定義一個大小為52的全0陣列。遍歷字串,以'a'=0~'z'=26並且'A'=27~'Z'=52 為陣列下標,每個字元出現一次相應的陣列位加1,如果陣列中出現大於1的數時,返回false;如果遍歷結束之後,陣列所有元素都是0或1,則返回 true。
-
-
2.如果是ASCII碼,那麼總共範圍就是128
-
3.如果是Unicode,沒有字元要求,那麼就老老實實排序再判斷
-
-
本題也可以直接使用字串索引查詢的方法來判斷 ( S.charAt() )
-
題目說明不使用額外的資料結構演算法,那麼這道題最本質的還是使用位運算(不太會位運算,敲,這就去學習一下)
3.2 程式碼
3.2.1 使用HashMap
class Solution {
public boolean isUnique(String astr) {
if(astr == null){
return true;
}
Map<Character,Integer> map = new HashMap<>();
for(int i = 0; i< astr.length();i++){
if(map.containsKey(astr.charAt(i))){
return false;
}
map.put(astr.charAt(i),i);
}
return true;
}
}
3.2.2 使用位運算
class Solution {
public boolean isUnique(String astr) {
int mark = 0;
for (int i = 0; i < astr.length() ; i++) {
//移動距離
int move = (int)astr.charAt(i) - 'a';
if ((mark & (1 << move) )!=0){
return false;
}else {
mark |=(1 << move);
}
}
return true;
}
3.3.3 使用索引比較的方法(初步思路優化)
class Solution {
public boolean isUnique(String astr) {
if(astr == null){
return true;
}
for(int i = 0;i < astr.length();i++){
for(int j = i+1;j < astr.length();j++){
if(astr.charAt(i) == astr.charAt(j)){
return false;
}
}
}
return true;
}
}
01.02. 判定是否互為字元重排
1、題目
給定兩個字串 s1
和 s2
,請編寫一個程式,確定其中一個字串的字元重新排列後,能否變成另一個字串。
2、初步作答
2.1 思路
一個字串重新排列,僅是字元順序變化,字串長度不變,s1 和 s2 長度應一致。排列過程中要記錄字串中字元是否已經使用,使用過的字元不可二次使用。最終,所有字元全部使用,則字串重排成功。
2.2 做法
- s2 如果由 s1 重新排列,那麼兩個字串長度一定相同。所以,如果字串長度不同,直接返回false;
- 新建一個數組,記錄字串中字元使用情況;
- 我們這裡使用 for 迴圈遍歷 s1 中每一個字元,如果字元排列使用,則相應下標陣列加 1 ;
- 比較陣列之和與字串長度是否匹配,匹配則返回 true,反之返回 false;
2.3 程式碼
class Solution {
public boolean CheckPermutation(String s1, String s2) {
if(s1.length() != s2.length()){
return false;
}
int[] num = new int[s1.length()];
for(int i = 0;i < s1.length();i++){
for(int j = 0;j < s2.length();j++){
if(num[j] == 1){
continue;
}
if(s1.charAt(i) == s2.charAt(j)){
num[j] = 1;
break;
}
}
}
int sum = 0;
for(int m = 0;m < s1.length();m++){
sum += num[m];
}
if(sum == s1.length()){
return true;
}else{
return false;
}
}
}
程式碼執行情況 |
---|
執行用時:0 ms, 在所有 Java 提交中擊敗了100.00%的使用者 |
記憶體消耗:39.1 MB, 在所有 Java 提交中擊敗了5.27%的使用者 |
通過測試用例:23 / 23 |
2.4 思考
這裡定義了一個數組,導致記憶體消耗偏大。所以程式碼優化上,應著重考慮降低記憶體消耗。
3、題目解析
3.1 字元陣列排序比較
class Solution {
public boolean CheckPermutation(String s1, String s2) {
char[] s1char = s1.toCharArray();
Arrays.sort(s1char);
char[] s2char = s2.toCharArray();
Arrays.sort(s2char);
return new String(s1char).equals(new String(s2char));
}
}
3.2 雜湊演算法
class Solution {
public boolean CheckPermutation(String s1, String s2) {
int len1 = s1.length(), len2 = s2.length();
if (len1 != len2)
return false;
HashMap<Character, Integer> dic = new HashMap<>();
for (int i = 0; i < len1; i++) {
dic.put(s1.charAt(i) , dic.getOrDefault(s1.charAt(i), 0) + 1);
}
for (int i = 0; i < len2; i++) {
dic.put(s2.charAt(i) , dic.getOrDefault(s2.charAt(i), 0) - 1);
}
for (int val : dic.values()) {
if (val != 0)
return false;
}
return true;
}
}
-
幾種方法在記憶體消耗上都有缺陷,如果有更好的演算法,可以告訴我,謝謝