剑指Offer-字符串

替换空格

题目描述

请实现一个函数,将一个字符串中的空格替换成 “%20”。例如,当字符串为 We Are Happy. 则经过替换之后的字符串为 We%20Are%20Happy。

  • 时间限制:1 秒
  • 空间限制:32768K

代码

/**
 * @author Think
 * @since 2016-12-19 11:18:00
 */
public class Solution {
    public String replaceSpace(StringBuffer str) {
        int tar = 32;
        String des = "%20";
        StringBuffer reStr = new StringBuffer();
        for (int i=0;ichar c = str.charAt(i);
            if (tar == c){
                reStr.append(des);
            }else {
                reStr.append(c);
            }
        }
        return reStr.toString();
    }

    public static void main(String[] args) {
        StringBuffer in = new StringBuffer("We Are Happy");
        System.out.println(new Solution().replaceSpace(in));
    }
}

《剑指Offer》版本-题目

剑指Offer书本中的题目要求入参格式不一样,因此实现方法也不一样。

void ReplaceBlank(char string[], int length){
  //TODO
}

就需要从后往前,逐字节移动替换字符。

《剑指Offer》-代码

public class Solution {
    public static void main(String[] args) {
        int length = 20;
        char[] string = new char[length];
        String str = "We are happy";
        for (int i = 0; i < str.length(); i++) {
            string[i] = str.charAt(i);
        }
        int pos = 0;
        while (string[pos]!='\0'){
            System.out.print(string[pos++]);
        }
        System.out.println();
        Solution solution = new Solution();
        solution.ReplaceBlank(string, length);
        pos = 0;
        while (string[pos]!='\0'){
            System.out.print(string[pos++]);
        }
    }

    public void ReplaceBlank(char[] string, int length) {
        if (string == null || length <= 0) {
            return;
        }
        int originalLength = 0;
        int numberOfBlank = 0;
        int i = 0;
        while (string[i] != '\0') {
            originalLength++;
            if (string[i] == ' ') {
                numberOfBlank++;
            }
            i++;
        }

        int newLength = originalLength + 2 * numberOfBlank;

        // length为原始字符串数组的长度,如果替换后的总长度newLength超过length,则肯定无法替换成功。
        if (newLength > length) {
            return;
        }

        int indexOdOriginal = originalLength;
        int indexOfNew = newLength;
        while (indexOdOriginal >= 0 && indexOfNew > indexOdOriginal) {
            if (string[indexOdOriginal] == ' ') {
                string[indexOfNew--] = '0';
                string[indexOfNew--] = '2';
                string[indexOfNew--] = '%';
            } else {
                string[indexOfNew--] = string[indexOdOriginal];
            }
            indexOdOriginal--;
        }
    }
}

正则表达式匹配

题目描述

请实现一个函数用来匹配包括’.’和’*’的正则表达式。模式中的字符’.’表示任意一个字符,而’*’表示它前面的字符可以出现任意次(包含 0 次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串 “aaa” 与模式 “a.a” 和 “ab*ac*a” 匹配,但是与 “aa.a” 和 “ab*a” 均不匹配。

  • 时间限制:1 秒
  • 空间限制:32768K

代码

public class Solution {
    public static void main(String[] args) {
        char[] s = "aa".toCharArray();
        char[] patten = "a*".toCharArray();
        Solution solution = new Solution();
        boolean result = solution.match(s, patten);
        System.out.println(result);
    }

    public boolean match(char[] str, char[] pattern) {
        if (str == null || pattern == null) {
            return false;
        }
        int i = 0, j = 0;
        return matchTwo(str, i, pattern, j);
    }

    // 注意出现""/"."/"*"/".*"/a*a等情况,需要随时判断数组是否越界。
    boolean matchTwo(char[] str, int i, char[] pattern, int j) {
        int len1 = str.length;
        int len2 = pattern.length;
        // 如果Str和pattern匹配字符均已经到达末尾,则匹配成功。
        if (i == len1 && j == len2) {
            return true;
        }
        // 如果str还没结束,而pattern已经匹配结束,则匹配失败。
        // 另一方面,如果str已经结束,而pattern位结束,不能判断匹配失败。
        // 如:pattern以*结尾,可以匹配0位。
        if (i < len1 && j == len2) {
            return false;
        }

        // 首先判断pattern的后一位是不是*:*会影响pattern前一位的判断。
        // - 如果第二位是*,分一下几类。
        // 1 匹配0位,则pattern后移2位。
        // 2 字符串匹配1位成功,继续匹配下一位,pattern因为*存在,j不变;
        // 3 只匹配1位,pattern后移2位。
        // 说实话,2和3非常相似。而且个人感觉有些情况同时适用于2和3,
        // 但可能只有一返回true,又因为通过||连接,从而结果为真。
        // 求明确清晰的解析,点拨迷雾。

        // 通过(j+1)
        if ((j + 1) < len2 && pattern[j + 1] == '*') {
            if ((i < len1 && pattern[j] == '.') || (i < len1 && str[i] == pattern[j])) {
                return matchTwo(str, i, pattern, j + 2) ||
                        matchTwo(str, i + 1, pattern, j) ||
                        matchTwo(str, i + 1, pattern, j + 2);
            } else {
                return matchTwo(str, i, pattern, j + 2);
            }
        } else {
            if ((i < len1 && pattern[j] == '.') || (i < len1 && str[i] == pattern[j])) {
                return matchTwo(str, i + 1, pattern, j + 1);
            } else {
                return false;
            }
        }
    }
}

字符流中第一个不重复的字符

题目描述

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符”go”时,第一个只出现一次的字符是”g”。当从该字符流中读出前六个字符“google”时,第一个只出现一次的字符是”l”。

  • 时间限制:1秒
  • 空间限制:32768K

这里的256是按照《剑指Offer》中说的8位的char类型。

代码

public class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
//        String str = "google";
//        String str = "";
//        String str = "aabbcc";
        String str = "think";
        for (int i=0;iint charTable[] = new int[256];
    StringBuffer sb = new StringBuffer();

    //Insert one char from stringstream
    public void Insert(char ch) {
        sb.append(ch);
        if (ch >= 256) {
            return;
        }
        charTable[ch]+=1;
    }

    //return the first appearence once char in current stringstream
    public char FirstAppearingOnce() {
        char defaultCh = '#';
        char charStr[] = sb.toString().toCharArray();
        for (int i=0;iif (charTable[charStr[i]]==1){
                return charStr[i];
            }
        }
        return defaultCh;
    }
}

表示数值的字符串

题目描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串 “+100”,”5e2”,”-123”,”3.1416” 和 “-1E-16” 都表示数值。 但是 “12e”,”1a3.14”,”1.2.3”,”+-5” 和 “12e+4.3” 都不是。

  • 时间限制:1秒
  • 空间限制:32768K

代码

枚举方式,很多个if嵌套,感觉不是很好。很冗长。不过确实可以体现解题思路。

public class Solution {
    public static void main(String[] args) {
        Solution solution = new Solution();
        // True for: "+100","5e2","-123","3.1416" and "-1E-16"
        // False for: "12e","1a3.14","1.2.3","+-5" and "12e+4.3"
        // Other test case: +.123, 1+23,
        char[] str = "1+23".toCharArray();
        System.out.println(solution.isNumeric(str));
    }

    public boolean isNumeric(char[] str) {
        int numOfPoint = 0;
        if (str == null) {
            return false;
        }

        int index = 0;
        if (str[index] == '+' || str[index] == '-') {
            index = 1;
            if (!isNumber(str[index]) && str[index] != '.') {
                return false;
            }
        }
        for (int i = index; i < str.length; i++) {
            if (str[i] == 'e' || str[i] == 'E') {
                if ((i + 1) < str.length && (str[i + 1] == '+' || str[i + 1] == '-') && (i + 2) < str.length && isNumber(str[i + 2])) {
                    index = i + 3;
                    break;
                } else if ((i + 1) < str.length && isNumber(str[i + 1])) {
                    index = i + 2;
                    break;
                } else {
                    return false;
                }
            } else if (str[i] == '.') {
                numOfPoint++;
                if (numOfPoint > 1) {
                    return false;
                }
            } else {
                if (!isNumber(str[i])) {
                    return false;
                }
            }
            index = i;
        }
        for (int i = index; i < str.length; i++) {
            if (!isNumber(str[i])) {
                return false;
            }
        }
        if (numOfPoint > 1) {
            return false;
        }
        return true;
    }

    public boolean isNumber(char ch) {
        if (ch < '0' || ch > '9') {
            return false;
        } else {
            return true;
        }
    }
}

看到有人的解题方法是使用Double.parseDouble(new String(str));方法,感觉不是很好,如果字符串表示的数值范围超出了Double呢?!

代码2

public class Solution {
    public boolean isNumeric(char[] str) {
        String s=String.valueOf(str);
        //return s.matches("[+-]?[0-9]*(.[0-9]*)?([eE][+-]?[0-9]+)?");
        return s.matches("[+-]?[0-9]*(\\.[0-9]*)?([eE][+-]?[0-9]+)?");
    }
}

简洁、简单明了。

有人提到可以使用“编译原理中自动机”实现,思路条理清晰,赞。

小结

注意上述几个问题的边界问题处理方式。null、空字符串、不符合要求的、符合要求的、多重符合题目要求的,均可以自己写出相应的字符串进行测试,防止程序出现异常而崩溃。

题目简单并不意味着代码简单。

你可能感兴趣的:(算法,Java)