Leetcode 字串 Easy Java 11道
花了一週早上的時間刷完了陣列+字串一共20道題,每天都有一些小的收穫,也是蠻不錯的感覺。下面我就字串這9道題談下我的解題思路:
(一)344 反轉字串:
題目內容:
難度等級:Easy
解題思路一:剛開始想著拼接字串的方式,反向讀取s的每個字元,然後賦值給新的字串,結果時間複雜度太高,通過不了。故而採用了將其轉為stringbuilder,呼叫reverse的API。要提前判斷為空的情況。
解題思路二:別人的方法:利用toCharArray將其轉為char型別陣列,重新賦值建立新陣列,反向遍歷賦值。而且時間複雜度更低。
程式碼:
// 1.剛開始想著拼接字串的方式,反向讀取s的每個字元,然後賦值給新的字串,結果時間複雜度太高,通過不了,故而採用 // 一定要提前判斷,會減少運算量,直接用stringbuilder中的reverse API。 // public static String reverseString(String s) { // if (s.length() == 0) { // return ""; // } // StringBuffer sb_01 = new StringBuffer(s); // sb_01.reverse(); // return sb_01.toString(); // } //2.將其轉為char型別陣列,利用重新賦值建立新陣列,反向讀取賦值,也可以搞定。而且時間複雜度更低。 public static String reverseString(String s) { char[] chars = s.toCharArray(); char[] newString = new char[chars.length]; for (int i = chars.length - 1, t = 0; i >= 0; i--, t++) { newString[t] = chars[i]; } return new String(newString); }
(二)7 顛倒整數:
題目內容:
難度等級:Easy
解題思路:這個題當時還挺麻煩的,注重細節太多。因為StringBuilder和StringBuffer的物件是變數,對變數進行操作就是直接對該物件進行更改,而不進行建立和回收的操作。故而使用StringBuilder來搞定。步驟如下:(1)判斷數字是否大於零,若小於零,則從下標為1開始擷取字串;(2)使用result +=(Math.pow(10,i)*tmp);tmp為正向讀取到的每個元素;result為long型別。(3)判斷其是否大於Integer.MAX_VALUE或者小於Integer.MIN_VALUE,返回相應的值。注意以下幾點:(1)MAth.abs不能用;(2)Integer.MAX_VALUE判斷最大值;(3)判斷反轉之後的有沒有越界,而不是之前的有沒有越界。
程式碼:
//StringBuilder和StringBuffer的物件是變數,對變數進行操作就是直接對該物件進行更改,而不進行建立和回收的操作,所以速度要比String快很多。 //md一定要注意越界問題,(1)MAth.abs不能用。(2)Integer.MAX_VALUE判斷最大值;(3)判斷反轉之後的有沒有越界,而不是之前的有沒有越界。 public static int reverse(int x) { StringBuilder sb_01; long result = 0; if (x >= 0) { sb_01 = new StringBuilder(String.valueOf(x)); } else { sb_01 = new StringBuilder(String.valueOf(x).substring(1, String.valueOf(x).length())); } for(int i = 0; i<sb_01.length();i++){ int tmp = Integer.parseInt(sb_01.substring(i,i+1)); result +=(Math.pow(10,i)*tmp); } if(result<Integer.MIN_VALUE || result>Integer.MAX_VALUE){ result = 0; } return x>0?(int)result:-(int)result; }
(三)387. 字串中的第一個唯一字元:
題目內容:
難度等級:Easy
解題思路一:(1)雙重迴圈遍歷並更改字串:遍歷一遍將重複元素都置為'A'.若有改變則將flag置為true,將new_str[i]最後也置為'A'。(2)迴圈遍歷字串,查詢第一個不等於‘A’的元素。注意:若被比較元素為‘A’,則不對其進行比較了,直接下一個,能加快效率。
解題思路二:別人的方法:比我的方法快十倍,思路比較清奇,主要是遍歷a-z的元素,記錄其第一次出現的位置和最後出現一次的位置是否相同,若相同,則說明只出現了一次,記錄該點位置,有更小的位置則對其不斷進行更新。若不同,則不用處理。最後判定如果全部相等的話就將其置為-1。
程式碼:
public static int firstUniqChar(String s) {
char[] new_str = s.toCharArray();
boolean flag = false;
//遍歷並更改字串。第一儘量減少複雜度;第二看清楚條件,若沒有結果輸出-1,而不是0.謝謝。
if (new_str.length != 0) {
for (int i = 0; i < s.length() - 1; i++) {
if (new_str[i] != 'A') {
for (int j = i + 1; j < s.length(); j++) {
//遍歷一遍將重複元素都置為'A'.若有改變則將flag置為true,提示將new_str[i]最後也置為'A'
if (new_str[i] == new_str[j]) {
flag = true;
new_str[j] = 'A';
}
}
if (flag) {
new_str[i] = 'A';
}
flag = false;
}
}
int result = -1;
for (int i = 0; i < s.length(); i++) {
if (new_str[i] != 'A') {
result = i;
break;
}
}
return result;
} else {
return -1;
}
}
//比我的時間加快十倍,思路比較清奇,主要是遍歷a-z的元素,記錄其第一次出現的位置和最後出現一次的位置是否相同,
// 若相同,則說明只出現了一次,記錄該點位置。並對其不斷進行更新,若不同,則不用處理。最後判定如果全部相等的話就將其置為-1。
// public static int firstUniqChar(String s) {
// int index=-1;
// int result=s.length();
// for(char ch='a';ch<='z';ch++){
// index=s.indexOf(ch);
// if (index!=-1&&index==s.lastIndexOf(ch)){
// result = result>index?index:result;
// }
// }
// return result> s.length()-1?-1:result;
// }
(四)242. 有效的字母異位詞:
題目內容:
難度等級:Easy
解題思路一:(1)字串轉陣列;2.利用API對陣列排序;3.對比陣列的每一個元素,判斷是否相等。
解題思路二:別人的方法:比我的快5倍。(1)建立兩個陣列,用於存放26個字元中每個元素出現的次數;(2)進行遍歷,若a出現了5次,則sArr[1]=5;(3)判斷兩個陣列每個位置是否相等。
//(1)字串轉陣列;2.利用API對陣列排序;3.對比陣列的每一個元素,判斷是否相等。
// public static boolean isAnagram(String s, String t) {
// if (s.length() == t.length()) {
// char[] arrays_01 = s.toCharArray();
// char[] arrays_02 = t.toCharArray();
// Arrays.sort(arrays_01);
// Arrays.sort(arrays_02);
// for(int i = 0;i<arrays_01.length;i++){
// if(arrays_01[i] != arrays_02[i]){
// return false;
// }
// }
// return true;
// } else {
// return false;
// }
// }
//比我的快5倍。(1)建立兩個陣列,用於存放26個字元中每個元素出現的次數;(2)進行遍歷,若a出現了5次,則sArr[1]=5;
//(3)判斷兩個陣列每個位置是否相等。
public static boolean isAnagram(String s, String t) {
int[] sArr = new int[26];
int[] tArr = new int[26];
for(char c : s.toCharArray()){
sArr[c - 'a']++;
}
for(char c : t.toCharArray()){
tArr[c - 'a']++;
}
for(int i=0;i<26;i++){
if(sArr[i] != tArr[i])
return false;
}
return true;
}
(五)125. 驗證迴文串:
題目內容:
難度等級:Easy
解題思路一:(1)建立新Arraylist陣列,正向遍歷,若為字母和數字,新增進去,形成新陣列。(2)再正向遍歷一遍,若arrayList_01.get(i)!=arrayList_01.get(arrayList_01.size()-1-i),則return false,只需要遍歷下標到arrayList_01.size()/2即可。
解題思路二:別人的方法:不額外使用別的儲存空間,利用本身的陣列從前面和後面同時遍歷,然後利用isLetterOrDigit和toLowerCase兩個API來具體計算。當low>=high時停止。
程式碼:
// public static boolean isPalindrome(String s) {
// ArrayList <Character>arrayList_01 = new ArrayList<Character>();
// if(s.length()>1) {
// for (int i = 0; i < s.length(); i++) {
// if ((s.charAt(i) >= 'a' && s.charAt(i) <= 'z') || (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z')
// || (s.charAt(i) >= '0' && s.charAt(i) <= '9')) {
// if (s.charAt(i) >= 'A' && s.charAt(i) <= 'Z') {
// arrayList_01.add((char) (s.charAt(i)+32));
// } else {
// arrayList_01.add(s.charAt(i));
// }
// }
// }
// for(int i = 0;i<arrayList_01.size()/2;i++){
// if(arrayList_01.get(i)!=arrayList_01.get(arrayList_01.size()-1-i)){
// return false;
// }
// }
// return true;
// }else{
// return true;
// }
// }
//2.他的方案是不額外使用別的儲存空間,利用本身的陣列從前面和後面同時遍歷,然後利用isLetterOrDigit和
// toLowerCase兩個API來具體計算。當low>=high是停止。
public static boolean isPalindrome(String s) {
if(s.isEmpty()){
return true;
}
int head=0,tail=s.length()-1;
char cHead,cTail;
while(head<tail){
cHead=s.charAt(head);
cTail=s.charAt(tail);
if(!Character.isLetterOrDigit(cHead)){
head++;
}
else if(!Character.isLetterOrDigit(cTail)){
tail--;
}
else{
if(Character.toLowerCase(cHead)!=Character.toLowerCase(cTail))
return false;
head++;
tail--;
}
}
return true;
}
(六)8. 字串轉整數 (atoi):
題目內容:
難度等級:Medium
解題思路一:Medium的題果然考慮更多,(一)將字串轉為字元陣列後,遍歷一遍陣列,設定標誌位並考慮以下五種情況:(1)若其為空格且flag為False時將其下標遞增;(2)若其為-號或+號時且flag為False時將其加進陣列中去;(3)若數字不在0-9之間,且flag為flase時,則跳出;(4)若在0-9時,將其加進陣列中去;(5)若flag為true時,若數字不在0-9,跳出。(二)檢查字串的有效性。字串長度為零等等;(三)利用try...catch轉換失敗的異常情況來搞定大於2^31的情況。
解題思路二:別人的方法:比我快兩倍,思路特別清晰:充分利用了trim()的API:(1)先判斷字串為空和str.trim長度為零的情況;(2)對trim之後的字串的第一個字元先判斷其+-;(3)然後在逐個讀取字元,若字元字元>=0<=9時計算res值;並進行累加;若大於MAx或<min時返回相應的最大最小值;若不是數字則break;(4)最後根據+-輸出相應的值,思路太清晰了有木有。
程式碼:
// public static int myAtoi(String str) {
// char[] new_str = str.toCharArray();
// boolean flag = false;
// String result = new String();
// 設定標誌位,分為四種情況。(1)若其為空格且flag為False時將其下標遞增;(2)若其為-號時且flag為False時將其加進陣列中去;
// (3)若數字不在0-9之間,且flag為flase時,則跳出;(4)若在時,將其加進陣列中去;(5)若flag為true時,若數字不在0-9,跳出
// for (int i = 0; i < new_str.length; i++) {
// if (new_str[i] == 32 && !flag) {
// continue;
// } else if (new_str[i] == 45 && !flag || new_str[i] == 43 && !flag) {
// result += new_str[i];
// flag = true;
// } else if ((new_str[i] < 48 && !flag) || (new_str[i] > 57 && !flag)) {
// break;
// } else if (new_str[i] >= 48 && new_str[i] <= 57) {
// result += new_str[i];
// flag = true;
// } else if (flag) {
// break;
// }
// }
// boolean flag_02 = false;
// if (result.length() != 0) {
// if ((result.charAt(0) != 45 && result.charAt(0) < 48 && result.charAt(0) != 43)
// || result.charAt(0) != 45 && result.charAt(0) != 43 && result.charAt(0) > 57) {
// flag_02 = true;
// }
// //檢驗字串的有效性,遍歷一遍
// for (int i = 1; i < result.length(); i++) {
// if (result.charAt(i) < 48 && result.charAt(i) > 57) {
// flag_02 = true;
// }
// }
// if (result.charAt(0) == 45 && result.length() == 1 || result.charAt(0) == 43 && result.length() == 1) {
// return 0;
// }
// } else {
// return 0;
// }
// long back_result;
// //這塊利用try...catch啊小哥哥,是不是傻。
// try {
// back_result = Long.parseLong(result);
// //輸出結果,如果<min_value,如果>max_value.如果正常情況下。
// } catch (Exception ee) {
// if (result.charAt(0) == '-')
// return Integer.MIN_VALUE;
// else
// return Integer.MAX_VALUE;
// }
//
// if (flag_02) {
// return 0;
// } else {
// if (back_result < Integer.MIN_VALUE) {
// return Integer.MIN_VALUE;
// } else if (back_result > Integer.MAX_VALUE) {
// return Integer.MAX_VALUE;
// } else {
// return (int) back_result;
// }
// }
// }
//比我快兩倍,思路特別清晰(1)先判斷字串為空和str.trim長度為零的情況;(2)對trim之後的字串先判斷其+-;
//(3)然後在逐個讀取字元,若字元字元>=0<=9時計算res值;若大於MAx或<min時返回相應的最大最小值;若不是數字則break;
//(4)最後判斷+-,思路太清晰。
public static int myAtoi(String str) {
if(str == null || str.trim().length() == 0) return 0;
long res = 0;
int flag = 1;
int i = 0;
String newstr = str.trim();
if(newstr.charAt(i) == '+') {
flag = 1;
i++;
}else if(newstr.charAt(i) == '-'){
flag = -1;
i++;
}
while(i < newstr.length()){
if(newstr.charAt(i) >= '0' && newstr.charAt(i) <= '9'){
res = res * 10 + (newstr.charAt(i++) - '0');
if(flag == 1 && res > Integer.MAX_VALUE) return Integer.MAX_VALUE;
if(flag == -1 && (flag * res) < Integer.MIN_VALUE) return Integer.MIN_VALUE;
}else{
break;
}
}
return flag == 1 ? (int)res : (int)(flag*res);
}
(七)28. 實現strStr()
題目內容:
難度等級及執行時間:Easy,812ms.
解題思路一:(1)判斷兩個string長度,若第一個小於第二個,則return -1;(2)記錄每次第一個相等位置的下標,然後在此基礎之上比較,若遍歷至第二個字串最後一個元素也相等,則結束,並return開始的位置,若中間不同,則break跳出;同時要防止第一個字串在遍歷過程中越界問題。(3)判斷第二個字串的長度不為零。第一遍未通過時未考慮到:(1)haystack的長度小於needle的長度;(2)在比較時,haystack獲取的位置不能越界。
解題思路二:別人的方法:好簡單,利用indexof的API即可解決,同時為了加快執行時間,先考慮needle長度為零和haystack長度為零的情況。
程式碼:
//未考慮到(1)haystack的長度小於needle的長度;(2)在比較時,haystack獲取的位置不能越界。
//解題思路:(1)判斷兩個string長度,若第一個小於第二個,則return -1;(2)記錄每次第一個相等位置的下標,
// 然後在此基礎之上比較,若遍歷至第二個字串最後一個元素也相等,則結束,並return開始的位置,若中間不同,則break跳出;
//同時要防止第一個字串在遍歷過程中越界問題。
//(3)判斷第二個字串的長度不為零。
//執行時間:812ms
// public static int strStr(String haystack, String needle) {
// int backresult = -1;
// if (haystack.length() < needle.length()) {
// return -1;
// }
// if (needle.length() != 0) {
// for (int i = 0; i < haystack.length(); i++) {
// int j;
// if (haystack.charAt(i) == needle.charAt(0)) {
// for (j = 0; j < needle.length(); j++) {
// if (i + j < haystack.length()) { //必須不能超過haystack的長度
// if (haystack.charAt(i + j) == needle.charAt(j)) {
// continue;
// } else {
// break;
// }
// }else{
// break;
// }
// }
// if (j == needle.length()) {
// return i;
// }
// }
// }
// return backresult;
// } else {
// return 0;
// }
// }
//利用indexof的API,去計算needle在haystack的位置,同時需要考慮needle長度為零和haystack長度為零的情況。執行時間:6ms
public static int strStr(String haystack, String needle) {
int m = needle.length();//needle字串的長度
if (m == 0) {
return 0;
} else {
if (haystack.length() == 0) {
return -1;
} else {
//return haystack.substr(needle); 不能直接採用substr函式,substr表示指定輸出從何處開始多長的子字串
return haystack.indexOf(needle);
}
}
}
(八)38. 報數:
題目內容:
難度等級及執行時間:Easy,9ms,超過55%。
解題思路一:這個題應該劃歸到medium裡面,光理解題意都得小半會。1.先對字串Stringbuilder進行分割,設定begin下標位置為0,(1)若字串中的字元前者不等於後者,則統計begin下標到該處的位置和字元,放進ArrayList中(Arraylist裡面存了數字和重複次數),更新begin的值;(2)若到了字串的結束位置,也將其儲存進去。 2.更新Stringbuilder內容,計算時候一定要細心,重複n-1次。
解題思路二:別人的方法:執行時間為2ms,不需要額外的空間。每一個數字內容已經確定,只需要統計他出現的次數。每次append(count).append(cha)可以完美解決,每次更新字串和新字元,重置統計個數。看程式碼哈哈哈哈。append()原來可以這麼玩。
程式碼:
public class Main {
public static void main(String[] args) {
// write your code here
int n = 4;
System.out.println(countAndSay(6));
}
// //執行時間2ms;
// //解題思路:不需要額外的空間。每一個數字內容已經確定,只需要統計他出現的次數。每次append(count).append(cha)
// // 可以完美解決,每次更新字串和新字元,重置統計個數。
// public static String countAndSay(int n) {
// int count = 1;
// String s = "1";
// while (count ++ < n) {
// s = readString(s);
// }
// return s;
// }
//
// private static String readString(String s) {
// char[] chs = s.toCharArray();
// char c = chs[0];
// int count = 1;
// StringBuilder sb = new StringBuilder();
// for (int i = 1; i < chs.length; i++) {
// if (chs[i] == c) {
// count ++;
// } else {
// sb.append(count).append(c);
// c = chs[i];
// count = 1;
// }
// }
//
// sb.append(count).append(c);
// return sb.toString();
// }
//執行用時:9 ms,超過55%。
//1.先對字串Stringbuilder進行分割,設定begin下標位置為0,若字串中的字元前者不等於後者,則統計begin下標到該處的位置和字元,放進ArrayList中;
//若到了字串的結束位置,則將其儲存進去(先判斷這個)
//2.更新Stringbuilder內容,計算時候一定要細心,重複n-1次。
public static String countAndSay(int n) {
String init_Str = "1";
StringBuilder init_stb = new StringBuilder(init_Str);
for (int j = 0; j < n-1; j++) {
int begin = 0; //記錄每個字串開始的位置。
ArrayList<stru> arrArrayList_01 = new ArrayList<stru>();
//對每個字串進行分割,分割成相應的ArrayList。
for (int i = 0; i < init_stb.length(); i++) {
if (i == init_stb.length() - 1) {
stru stru_01 = new stru();
stru_01.array_con = init_stb.charAt(i);
stru_01.array_amo = init_stb.length() - begin;
arrArrayList_01.add(stru_01);//將長度和內容存進數組裡面。
} else if (init_stb.charAt(i) != init_stb.charAt(i + 1)) {
stru stru_01 = new stru();
stru_01.array_con = init_stb.charAt(i);
stru_01.array_amo = i + 1 - begin;
arrArrayList_01.add(stru_01);//將長度和內容存進數組裡面。
begin = i + 1;//更新分割字串開始的位置。
}
}
//更新舊陣列內容。
for (int i = 0; i < arrArrayList_01.size(); i++) {
init_stb.replace(i * 2, i * 2 + 1, String.valueOf(arrArrayList_01.get(i).array_amo));
init_stb.replace(i * 2 + 1, i * 2 + 2, String.valueOf(arrArrayList_01.get(i).array_con));
}
}
return init_stb.toString();
}
}
class stru {
char array_con;//內容
int array_amo;//數量
}
(九)14. 最長公共字首:
題目內容:
難度等級及執行時間:Easy,12ms。
解題思路一:(1)先找到最小字串的長度,然後記錄下來;(2)以最小長度為外層迴圈。以陣列長度為內層迴圈,進行遍歷,若該位前者等於後者,則累加字串,並對比第二個和第三個字串的第一位。若不等,則break,設定flag,告訴系統結束了;若最後一個字串等於陣列長度,則對比下一位。(第一次提交時未考慮到:若陣列長度為空,則返回空字串;若長度為1,則返回第一個陣列的全部字串)。
解題思路二:別人的方法:執行用時:6 ms。思路比較清奇,充分利用了indexof的API。(1)若字元陣列長度為零,則return空;(2)記錄陣列第一個元素為result;(3)對後面的每個字串進行遍歷,若indexof()不為零,則擷取字串(0,s.length()-1),若為零,則對下一個字串進行indexof(s)。
程式碼:
//解決方法:1.先找到最小字串的長度,然後記錄下來;2.以最小長度為外層迴圈。以陣列長度為內層迴圈,進行遍歷,
// 若該位前者等於後者,則累加字串,並對比第二個和第三個字串的第一位。若不等,則break,設定flag,告訴系統結束了;如果最後一個字串
// 等於陣列長度,則對比下一位。(第一次提交時未考慮到:若陣列長度為空,則返回空字串;若長度為1,則返回第一個陣列的全部字串
// 執行用時:12 ms
// public static String longestCommonPrefix(String[] strs) {
// if(strs.length == 0) return "";
// if(strs.length == 1) return strs[0];
// String result = new String();
// int min = strs[0].length();
// for (int i = 1; i < strs.length; i++) {
// if (min > strs[i].length()) {
// min = strs[i].length();
// }
// }
// boolean flag = false;
// for (int i = 0; i < min; i++) {
// for(int j = 0;j<strs.length-1;j++){
// if(strs[j].charAt(i) == strs[j+1].charAt(i)){
// if(j==strs.length-2){
// result += strs[j].charAt(i);
// }
// continue;
// }else{
// flag =true;
// break;
// }
// }
// if(flag) break;
// }
// return result;
// }
// 執行用時:6 ms
//1。若字元陣列長度為零,則return 空;2.記錄第一個陣列為result;3.對後面的每個字串進行遍歷,若indexof()
//不為零,則對s-1,遍歷陣列內所有字串,若不包含,則--,若包含,則下一個字串。很清奇的思路。充分利用了indexof的API。
public static String longestCommonPrefix(String[] strs) {
if (strs.length == 0) {
return "";
}
String s = strs[0];
for (int i = 1; i < strs.length; i++) {
while (strs[i].indexOf(s) != 0) {
s = s.substring(0, s.length() - 1);
if (s.isEmpty()) {
return "";
}
}
}
return s;
}