[LeetCode]-字符串-2

前言

记录 LeetCode 刷题时遇到的字符串相关题目,第二篇

165. 比较版本号

使用 String 的 split 方法以 ‘.’ 将字符串划分为不同部分,每一部分转化为数字再根据题意进行比较即可

public int compareVersion(String version1, String version2) {
    String[] s1 = version1.split("\\.");
    String[] s2 = version2.split("\\.");
    int i = 0;
    while(i < s1.length || i < s2.length){
        int num1 = i < s1.length ? Integer.valueOf(s1[i]) : 0;
        int num2 = i < s2.length ? Integer.valueOf(s2[i]) : 0;
        if(num1 > num2) return 1;
        if(num1 < num2) return -1;
        i++;
    }
    return 0;
}

8.字符串转换整数(atoi)-模拟

首先:long的范围为-9223372036854775808~9223372036854775807
根据题意以及案例模拟就可以了。要注意的点,题目说到计算结果可能会超出int的范围,所以在保存运算的中间结果时先用long类型的res变量来保存,对字符串处理完毕后对res判断是否超出int范围即可;还有一个点就是计算过程还可能超出long的范围,比如输入"9223372036854775808"这个样例,所以对每个原酸得到的中间变量都可以判断是否超出int范围,超出就不用继续往下算了,直接可以判断后返回结果,也就不用担心后面在超出long的范围了

public int myAtoi(String s) {
    int length = s.length();
    if(length == 0) return 0;
    int index = 0;
    //去除前导空格,注意不能用" ".equals(s.charAt(index))来判断
    while(index < length && ' ' == (s.charAt(index))){
        index++;
    }
    //去除空格后字符串就结尾了,返回0
    if(index == length) return 0;
    //检查下一个字符符号,是负号则结果应为负号;其他符号的话结果都为正号
    //flag置为0表示负号,1表示正号
    int flag;
    if(s.charAt(index) == '-') flag = 0;
    else flag = 1;
    //开始读入字符
    long res = 0L;
    int temp = index;
    //如果上一步检查到的符号是正号或负号,那就要从下一个字符开始读取数字;如果是数字或其他字符就直接从这一个字符开始读
    if(s.charAt(temp) == '-' || s.charAt(temp) == '+') temp++;
    while(temp < length){
        char c = s.charAt(temp);
        if(c >= '0' && c <= '9'){
            res *= 10;
            res += Integer.parseInt(String.valueOf(c));
            //已经溢出int的范围不用继续计算
            if(res > Integer.MAX_VALUE || res < Integer.MIN_VALUE) break;
            temp ++;
        }else{
        	//遇到非数字字符直接结束
            break;
        }
    }
    res = flag == 0 ? -res : res;
    if(res > Integer.MAX_VALUE) return Integer.MAX_VALUE;
    else if(res < Integer.MIN_VALUE) return Integer.MIN_VALUE;
    return (int)res;
}

43. 字符串相乘

根据乘法运算的法则,将 num1 与 num2 的每一位都做一次乘法,会得到 num2.length() 个结果,将这些结果相加得到的就是答案。相加可以使用 415. 字符串相加 的做法

注意乘法运算的每一个结果都不能使用 int 或 long 直接保存,因为有些样例运算的结果甚至超过了 long 的范围。所以只有每一位的运算可以使用 int 进行,其余的运算都只能使用字符串

class Solution {
    public String multiply(String num1, String num2) {
        int l1 = num1.length();
        int l2 = num2.length();
        //判断是否有零,有则乘法运算结果为0
        boolean num1IsZero = l1 == 1 && num1.charAt(0) == '0';
        boolean num2IsZero = l2 == 1 && num2.charAt(0) == '0';
        if(num1IsZero || num2IsZero) return "0";
        
        char[] c1 = num1.toCharArray();
        char[] c2 = num2.toCharArray();
        int more = 0,cur = 0; //more表示每一位运算得到的进位,cur表示每一位运算的结果
        //num1与num2的十位,百位,...等高位运算时得到的结果后面需要补0,表示10倍,100倍,...
        StringBuilder tmpTimes = new StringBuilder();
        StringBuilder tmp = null; //表示num1与num2每一位乘法运算时得到的结果
        String res = ""; //保存num1与num2每一位乘法运算后的结果相加得到的累积结果
        //外层循环为num2
        for(int i = l2 - 1;i >= 0;i--){
            more = 0;
            tmp = new StringBuilder();
            //内层循环为num1
            for(int j = l1 - 1;j >= 0;j--){
                cur = (c1[j] - '0') * (c2[i] - '0') + more;  //乘法运算
                more = cur / 10; //得到进位
                cur = cur % 10;  //减去进位得到该位的结果
                //新一位的运算结果应放在tmp的最高位,所以需要反转一下
                tmp = tmp.reverse().append(cur).reverse(); 
            }
            //最高位可能有进位不要忘了
            if(more > 0) tmp = tmp.reverse().append(more).reverse();
            //tmp补0后与原先的res相加
            res = addStrings(tmp.append(tmpTimes).toString(),res);
            tmpTimes.append("0"); //随着num2参与运算的数的位数增加,所需补的0也需增加
        }
        return (res);
    }
    public String addStrings(String num1, String num2) {
	   char[] c1 = num1.toCharArray();
	   int index1 = c1.length - 1; //转换为字符数组的话下标从大到小遍历
	   char[] c2 = num2.toCharArray();
	   int index2 = c2.length - 1;
	   int more = 0,cur = 0;
	   StringBuilder res = new StringBuilder("");
	   while(index1 >= 0 || index2 >= 0){
           if(index1 < 0) cur = c2[index2--] - '0' + more; 
           else if(index2 < 0) cur = c1[index1--] - '0' + more;
           else cur = c1[index1--] - '0' + c2[index2--] - '0' + more;
           more = 0;
           if(cur > 9){
               more = 1;
               cur -= 10;
           }
           res.append((char)(cur + '0'));
       }
	   if(more > 0) res.append(more);
	   return res.reverse().toString();
	}
}

394. 字符串解码

这种嵌套结构很适合使用栈或者递归来做。这里采用递归来做:

定义一个递归方法 getStr(String s,int index),返回从下标 index 开始的完整编码字符串经过解码后的字符串,就算其中有嵌套其它的 ‘[’,‘]’ 也可以。所以入口函数 decodeString 只需调用 getStr 即可

从 index 开始遍历 s,遇到 ‘[’,就对这个 ‘[’ 后面的内容递归调用 getStr 方法获取这个 ‘[’ 对应的解码后字符串 str。根据题意,‘[’ 之前一定是个数字,所以在遇到这个 ‘[’ 之前我们应该事先能知道这个 ‘[’ 之前的数字 num,那么这个解码后字符串 str 就需要重复 num 次。在 getStr 返回后,我们需要接着这次 getStr 已经遍历到的位置往后遍历,因此 getStr 还需要返回方法返回时遍历到的位置下标。由于 getStr 是查找 ‘[’ 和 ‘]’ 之间的字符串,所以 getStr 最后遍历到的元素一定是 ‘]’

遇到数字字符,就找到后续连续的数字字符计算整个连续的字符序列所代表的数字

遇到 ‘]',说明本次 getStr 的任务已经完成,返回得到的解码后字符串和这个 ‘]’ 的下标

最后就是遇到小写英文字母,直接 append 到 res 即可,res 即我们维护的本次 getStr 所找到的解码后字符串

需要注意的是,字符串拼接应使用 StringBuilder 来 append

class Solution {
    public String decodeString(String s) {
        return getStr(s,0)[0];
    }
    public String[] getStr(String s,int index){
        if(index == s.length()) return null;
        StringBuilder res = new StringBuilder();
        char[] cs = s.toCharArray();
        int num = 0;
        while(index < s.length()){
            if(cs[index] == '['){
                String[] strs = getStr(s,index + 1);
                while(num-- > 0){
                    res.append(strs[0]);
                }
                //getStr返回的是']'的下标,继续遍历需要从下一个字符开始
                index = Integer.parseInt(strs[1]) + 1;
            }else if(cs[index] >= '0' && cs[index] <= '9'){
                num = 0;
                while(cs[index] >= '0' && cs[index] <= '9'){
                    num = num * 10 + cs[index++] - '0'; //数字字符转换为对应的数字直接减去'0'即可
                }
            }else if(cs[index] == ']'){
                return new String[]{res.toString(),String.valueOf(index)};
            }else{
                res.append(cs[index++]);
            }
        }
        return new String[]{res.toString(),String.valueOf(index)};
    }
}

205. 同构字符串

一开始没看到题意的 “同时不改变字符的顺序”,以为只要字母的个数对得上就可以

使用两个哈希表 mapS,mapT,使用数组的形式,大小都为 256,因为题目说到 “s 和 t 由任意有效的 ASCII 字符组成”,所以数组每个槽上表示一个字符对应于另一个字符串中所要映射的字符,如 mapS[‘a’] = ‘b’,表示 s 中映射到 t 中的字符为 b

遍历两个字符串,同时建立两个字符串间字符的映射关系,如果遍历到一个字符在另一个字符串中对应位置的字符与已经建立的映射关系不符,则说明两个字符串不是同构字符串

public boolean isIsomorphic(String s, String t) {
    char[] mapS = new char[256];
    char[] mapT = new char[256];
    char[] charsS = s.toCharArray();
    char[] charsT = t.toCharArray();
    for(int i = 0;i < charsS.length;i++){
    	//判断映射关系是否被破坏,是则直接返回false
        if(mapS[charsS[i]] != 0 && mapS[charsS[i]] != charsT[i] || 
        mapT[charsT[i]] != 0 && mapT[charsT[i]] != charsS[i]){
            return false;
        }
        mapS[charsS[i]] = charsT[i];
        mapT[charsT[i]] = charsS[i];
    }
    return true;
}

14. 最长公共前缀

初始化一个字符串 prefix 为 strs[0],然后遍历 strs 中剩下的每个字符串跟 prefix 得到新的最长公共前缀,对比完所有字符串后得到的 prefix 就是最后的最长公共前缀

在枚举对比的过程中,如果得到最长公共前缀已经为空串了,后面就不用继续对比了,最后的最长公共前缀一定就是空串了

class Solution {
    public String longestCommonPrefix(String[] strs) {
        //strs一定包含1个或以上个元素,不用判断是否为null或是否不含元素
        String prefix = strs[0];
        int count = strs.length;
        for (int i = 1; i < count; i++) {
            prefix = longestCommonPrefix(prefix, strs[i]);
            //如果已经找到最长公共前缀为空串就不用继续找后面的字符串了
            if (prefix.length() == 0) {
                break;
            }
        }
        return prefix;
    }
    public String longestCommonPrefix(String str1, String str2) {
        int length = Math.min(str1.length(), str2.length());
        int index = 0;
        while (index < length && str1.charAt(index) == str2.charAt(index)) {
            index++;
        }
        return str1.substring(0, index);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值