Leetcode之字符串(一)

目录

1.length-of-last-word

2.add-binary

3.multiply-strings

4.valid-number

5.string-to-integer-atoi

6.roman-to-integer

7.integer-to-roman

8.implement-strstr

9.longest-substring-without-repeating-characters

10.longest-palindromic-substring


1.length-of-last-word

题目:给出一个只包含大小写字母和空格的字符串s,请返回字符串中最后一个单词的长度,如果字符串中没有最后一个单词,则返回0。注意:单词的定义是仅由非空格字符组成的字符序列。例如:s ="Hello World",返回5。

分析:先用String的trim()方法去掉前后的空格,反向遍历进行计算倒数第一个单词的长度即可。

   public int lengthOfLastWord(String s) {
        s = s.trim();
        int count = 0;
        for(int i = s.length() - 1;i >= 0;i--){
            if(s.charAt(i) == ' ')
                break;
            count++;
        }
        return count;
    }

2.add-binary

题目:给出两个用字符串表示的二进制数,返回他们的和(也用字符串表示)。例如:a ="11",b ="1",返回"100".

分析:先在短的字符串前面填充0让两字符串长度相同,从后往前依次相加即可,二进制相加可以用异或进行计算,可提高计算效率。

   public String addBinary(String a, String b) {
        if(a.length() == 0 || b.length() == 0)
            return a + b;
        int len = Math.max(a.length(),b.length());
        while(a.length() < len)
            a = "0" + a;
        while(b.length() < len)
            b = "0" + b;
        String result = "";
        int flag = 0;
        for(int i = len - 1;i >= 0;i--){
            int m = a.charAt(i) - '0',n = b.charAt(i) - '0';
            result = (m ^ n ^ flag) + result;
            if(m + n + flag < 2)
                flag = 0;
            else
                flag = 1;
        }
        if(flag == 1)
            result = 1 + result;
        return result;
    }

3.multiply-strings

题目:给出两个用字符串表示的数字,将两个数字的乘积作为字符串返回。备注:数字可以无限大,且是非负数。

分析:分治法。先举个简单的例子来说,比如99 * 33实际上会等于90 * 33 + 9 * 33,也就是把99从中间拆分,分别乘以33.所以我们可以将大数相乘a和b中的其中一个数从中间进行拆分,假设我们将a前后拆成a1、a2,那么就将问题拆成了a1*b,a2*b,最后结果就是a1*b后面添加a2.length个0与a2*b的和,问题又转化成了大数相加的问题。对于大数相加问题,可以将两个数字的后八位分离出来进行相加,再与数字其它位数的和进行拼凑,注意拼凑时有可能后8位数字相加之后的长度小于8,这时我们要进行补0,有可能长度大于9,也就是最高位为1时,这时我们要将高位数之和加上1,再与剩下8位进行拼凑。Integer.MAX_VALUE为2147483647,所以当两个数的长度均小于等于4时才进行直接相乘,长度小于等于8时才进行直接相加,以防止溢出。

     public String multiply(String num1, String num2) {
        int len1 = num1.length(),len2 = num2.length();
        if(len1 <= 4 && len2 <= 4)//递归出口
            return Integer.parseInt(num1) * Integer.parseInt(num2) + "";
        if(len1 > 4){//将长度大于4的字符串从中间进行拆分
            int mid = len1 >> 1;
            String s1 = num1.substring(0,mid);
            String s2 = num1.substring(mid);
            return add(multiply(s1,num2) + zero(s2.length()),multiply(s2,num2));
        }
        return multiply(num2,num1);
    }

    private String add(String num1, String num2) {//大数相加
        int len1 = num1.length(),len2 = num2.length();
        if(len1 <= 8 && len2 <= 8)//递归出口
            return Integer.parseInt(num1) + Integer.parseInt(num2) + "";
        String a1 = "0",a2 = num1;
        if(len1 > 8) {//分离出num1后8位
            a1 = num1.substring(0,len1 - 8);
            a2 = num1.substring(len1 - 8);
        }
        String b1 = "0",b2 = num2;
        if(len2 > 8) {//分离出num2后8位
            b1 = num2.substring(0,len2 - 8);
            b2 = num2.substring(len2 - 8);
        }
        String result = add(a2,b2);
        if(result.length() > 8)
            return add(add(a1,b1),"1") + result.substring(1);
        else
            return add(a1,b1) + zero(8 - result.length()) + result;
    }

    private String zero(int n){//返回n个0的字符串
        if(n == 0) return "";
        if(n == 1) return "0";
        String s = zero(n / 2);
        return s + s + zero(n % 2);
    }

4.valid-number

题目:判断给出的字符串是否是数字。一些例子:"0"=>true;" 0.1 "=>true;"abc"=>false;"1 a"=>false;"2e10"=>true

分析:见剑指offer面试题20 https://blog.csdn.net/Nibaby9/article/details/103822794

5.string-to-integer-atoi

题目:实现函数 atoi 。函数的功能为将字符串转化为整数。提示:仔细思考所有可能的输入情况。这个问题故意描述的很模糊(没有给出输入的限制),你需要自己考虑所有可能的情况。

分析:见剑指offer面试题67 https://blog.csdn.net/Nibaby9/article/details/103822794

6.roman-to-integer

题目:请将给出的罗马数字转化为整数,保证输入的数字范围在1 到 3999之间。

分析:罗马数字转换规则:I --> 1、V --> 5、X --> 10、L --> 50、C --> 100、D --> 500、M --> 1000,单个符号重复多少次,就表示多少倍。最多重复3次,比如:CCC表示300 XX表示20,但150并不用LLL表示,这个规则仅适用于I X C M;如果相邻级别的大单位在右,小单位在左,表示大单位中扣除小单位,比如:IX表示9 IV表示4 XL表示40。这里用暴力破解法,IV:4 IX:9 XL:40 XC:90 CD:400 CM:900这种组合实际上在罗马数中只会出现一次,所以可以遇到这种组合可以在计算的和中减去多加的数,比如说IV如果用I+V的值就为6,只要再减去2即可。

   public int romanToInt(String s) {
        int sum = 0;
        for(int i = 0;i < s.length();i++) {
            char c = s.charAt(i);
            if(c == 'I') sum+=1;
            if(c == 'V') sum+=5;
            if(c == 'X') sum+=10;
            if(c == 'L') sum+=50;
            if(c == 'C') sum+=100;
            if(c == 'D') sum+=500;
            if(c == 'M') sum+=1000;
        }
        if(s.contains("IV") || s.contains("IX"))//4、9
            sum -= 2;
        if(s.contains("XL") || s.contains("XC"))// 40、90
            sum -= 20;
        if(s.contains("CD") || s.contains("CM"))// 400、900
            sum -= 200;
        return sum;
    }

7.integer-to-roman

题目:请将给出的整数转化为罗马数字,保证输入数字的范围在1 到 3999之间。

分析:利用穷举法,将各位数分别转换为罗马数字即可。

    public String intToRoman(int num) {
        String[] one = {"","I","II","III","IV","V","VI","VII","VIII","IX"};
        String[] two = {"","X","XX","XXX","XL","L","LX","LXX","LXXX","XC"};
        String[] three = {"","C","CC","CCC","CD","D","DC","DCC","DCCC","CM"};
        String[] four = {"","M","MM","MMM"};
        String result = "";
        result += four[num / 1000];
        result += three[num % 1000 / 100];
        result += two[num % 100 / 10];
        result += one[num % 10];
        return result;
    }

8.implement-strstr

题目:实现函数 strStr。函数声明如下:char *strStr(char *haystack, char *needle),返回一个指针,指向needle第一次在haystack中出现的位置,如果needle不是haystack的子串,则返回null。例如"mississippi","issi",返回"ississippi".

分析:考查KMP算法,它是一种改进的字符串模式匹配算法,可以在O(n+m)的时间复杂度以内完成字符串的匹配操作,其核心思想在于当一趟匹配过程中出现字符不匹配时,不需要回溯主串的指针,而是利用已经得到的“部分匹配”,将模式串尽可能多地向右“滑动”一段距离,然后继续比较。KMP算法先计算模式串的next数组,next[i]表示模式串前i个字符的部分匹配值(”前缀”和”后缀”的最长的公有元素的长度),如”A”的前缀和后缀都为空集,部分匹配值为0,“ABCDAB”的部分匹配值为2。求解next数组的步骤:

  • 初始化next[0]=-1, next[1]=0;(注意如果初始化next[1]的话,需保证next数组长度至少为2,所以可以暂不初始化next[1])
  • 求解next[j]时,令k=next[j-1];
  • 比较T[j-1]与T[k]的值:若相等,则next[j] = k +1;否则令k=next[k],若k等于-1,则next[j]=0,否则跳转到第三步。

求解完next数组后,开始遍历主串来匹配模式串,如果不匹配则利用next数组进行对模式串进行偏移。

    public String strStr(String haystack, String needle) {
        if(needle.length() == 0)
            return haystack;
        if(needle.length() > haystack.length())
            return null;
        int[] next = cal_next(needle);
        int i = 0,j = 0;
        while(i < haystack.length() && j < needle.length()){
            if(haystack.charAt(i) == needle.charAt(j) ){
                i++;j++;
            }
            else if(next[j] == -1){
                j = 0;i++;
            }
            else
                j = next[j];
        }
        if(j == needle.length())
            return haystack.substring(i-j);//易错
        return null;
    }

    private int[] cal_next(String needle) {
        int[] next = new int[needle.length()];
        next[0] = -1;//初始化
        for(int i = 2;i < needle.length();i++){
            int k = next[i-1];
            while(k != -1 && needle.charAt(i-1) != needle.charAt(k))
                k = next[k];
            next[i] = k + 1;
        }
        return next;
    }

9.longest-substring-without-repeating-characters

题目:给定一个字符串,找出最长的不具有重复字符的子串的长度。例如,“abcabcbb”不具有重复字符的最长子串是“abc”,长度为3。对于“bbbbb”,最长的不具有重复字符的子串是“b”,长度为1。

分析:见剑指offer面试题48 https://blog.csdn.net/Nibaby9/article/details/10382279

10.longest-palindromic-substring

题目:找出给出的字符串S中最长的回文子串。假设S的最大长度为1000,并且只存在唯一解。

分析:动态规划。定义一个函数f(i,j)表示字符串第i个位置到第j个位置是否为回文串,从左到右依次扫描字符将其作为子串的结束位置,让子串往前进行延伸,在计算f(i,j)时就可保证f(i+1,j-1)已计算出,那么f(i,j) = (s.charAt(i) == s.charAt(j) && f(i+1,j-1))。

    public String longestPalindrome(String s) {
        if(s.length() == 0)
            return s;
        int max = 1;
        int start = 0;//保存最长回文子串的起始点
        boolean [][]dp = new boolean[s.length()][s.length()];//子串s[i..j] 是否是回文子串
        for(int i = 0;i < s.length();i++)
            dp[i][i] = true;
        for(int j = 1;j < s.length();j++){//子串结束位置
            for(int i = j-1;i >= 0;i--){//子串开始位置
               if(j - i < 2)
                   dp[i][j] = s.charAt(i) == s.charAt(j);
               else
                   dp[i][j] = (s.charAt(i) == s.charAt(j) && dp[i+1][j-1]);
               if(dp[i][j] && j-i+1 > max){
                   max = j - i + 1;
                   start = i;
               }
            }
        }
        return s.substring(start,start + max);
    }
发布了48 篇原创文章 · 获赞 7 · 访问量 6011

猜你喜欢

转载自blog.csdn.net/Nibaby9/article/details/104525641