1. 程式人生 > >Leetcode 字串 Easy Java 11道

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;
    }