Leetcode 字符串 Easy Java 11道

安卓开发及安全交流QQ群:838650234,感兴趣的可以加群。

       花了一周早上的时间刷完了数组+字符串一共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;
    }

猜你喜欢

转载自blog.csdn.net/weixin_38244174/article/details/82711940