leetcode题解-459. Repeated Substring Pattern && 443. String Compression && 434. Number of Segments in

459,Repeated Substring Pattern题目:

Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.

Example 1:
Input: "abab"

Output: True

Explanation: It's the substring "ab" twice.
Example 2:
Input: "aba"

Output: False
Example 3:
Input: "abcabcabcabc"

Output: True

Explanation: It's the substring "abc" four times. (And the substring "abcabc" twice.)

这道题感觉跟昨天的686. Repeated String Match挺像的,不过改成了判断一个字符串是否可以有自身的一个子串重复构造而成,很简单,一个最基本的要求就是字符串本身的长度应该是子串长度的整数倍,有了这个我们就可以写出下面这段简单高效的代码:

    //80%,可以击败80%的用户
    public static boolean repeatedSubstringPattern(String s) {

        int len = s.length();
        //i表示将s等分成i份,并且从小到大遍历,这样子字符串从长到短,可以节省判断次数
        for(int i=2; i<=len; i++){
            //必须整除才可以
            if(len%i == 0){
                int count = len / i, j;
                //遍历分成的几份子串是否完全相等,相等即表明可分
                for(j=0; j<i-1; j++){
                    if(!s.substring(j*count, (j+1)*count).equals(s.substring((j+1)*count, (j+2)*count)))
                        break;
                }
                if(j == i-1)
                    return true;
            }
        }
        return false;
    }

除了这种思路,我们还可以使用正则表达式以及一个很巧妙的想法,就是把S直接本身拼接,然后判断拼接后的字符串从1开始的子串T是否包含S,因为如果S可以由一个子串拼接而成,那么新构造的子串T一定是包含S的,我本来以为这种方法效率会很高,但是发现只能击败37%的用户,可能是因为contains函数比较耗时吧。代码如下所示:

    //37%
    public boolean repeatedSubstringPattern2(String str) {
        String s = str + str;
        return s.substring(1, s.length() - 1).contains(str);
    }

    //14%
    public boolean repeatedSubstringPattern1(String str) {
        if(str == null || str.length() < 2) return false;

        boolean result = false;
        for(int i = 1; i <= str.length()/2; i++) {
            if(str.length()%i != 0) continue;
            String regex = "("+str.substring(0,i)+")" + "+";
            result = result | str.matches(regex);
        }
        return result;
    }

最后还有一种高效的解法,使用KMP算法来求解,可以击败88%的用户,至于KMP算法后面应该会专门写一篇博客来介绍,就不在这里多说,直接看代码:

    //88%
    public boolean repeatedSubstringPattern3(String str) {
        //This is the kmp issue
        int[] prefix = kmp(str);
        int len = prefix[str.length()-1];
        int n = str.length();
        return (len > 0 && n%(n-len) == 0);
    }

    private int[] kmp(String s){
        int len = s.length();
        int[] res = new int[len];
        char[] ch = s.toCharArray();
        int i = 0, j = 1;
        res[0] = 0;
        while(i < ch.length && j < ch.length){
            if(ch[j] == ch[i]){
                res[j] = i+1;
                i++;
                j++;
            }else{
                if(i == 0){
                    res[j] = 0;
                    j++;
                }else{
                    i = res[i-1];
                }
            }
        }
        return res;
    }

接下来看443题目:

Given an array of characters, compress it in-place.

The length after compression must always be smaller than or equal to the original array.

Every element of the array should be a character (not int) of length 1.

After you are done modifying the input array in-place, return the new length of the array.


Follow up:
Could you solve it using only O(1) extra space?


Example 1:
Input:
["a","a","b","b","c","c","c"]

Output:
Return 6, and the first 6 characters of the input array should be: ["a","2","b","2","c","3"]

Explanation:
"aa" is replaced by "a2". "bb" is replaced by "b2". "ccc" is replaced by "c3".
Example 2:
Input:
["a"]

Output:
Return 1, and the first 1 characters of the input array should be: ["a"]

Explanation:
Nothing is replaced.
Example 3:
Input:
["a","b","b","b","b","b","b","b","b","b","b","b","b"]

Output:
Return 4, and the first 4 characters of the input array should be: ["a","b","1","2"].

Explanation:
Since the character "a" does not repeat, it is not compressed. "bbbbbbbbbbbb" is replaced by "b12".
Notice each digit has it's own entry in the array.
Note:
All characters have an ASCII value in [35, 126].
1 <= len(chars) <= 1000.

这道题跟昨天的38. Count and Say很像,就是一个统计连续字符长度,然后使用数字表示的题目。接发也非常简单,就不多说了:

    //46%
    public static int compress(char[] chars) {
        if(chars == null || chars.length <= 0)
            return 0;

        char var = chars[0];
        int left=0, right=0;
        for(int i=0; i<chars.length;){
            right = i;
            //统计相同字符连续出现次数
            while(right<chars.length && chars[right] == var) right ++;
            int len = right - i;
            //先写入字符
            chars[left++] = var;
            //如果长度不为1,在将出现次数以char型写入
            if(len != 1) {
                char[] tmp = String.valueOf(len).toCharArray();
                for(char num : tmp)
                    chars[left++] = num;
            }
            //遍历到最后一个元素结束循环
            if (right >= chars.length)
                break;
            i = right;
            var = chars[right];
        }
        return left;
    }

最后我们来看一下434. Number of Segments in a String的题目:

Count the number of segments in a string, where a segment is defined to be a contiguous sequence of non-space characters.

Please note that the string does not contain any non-printable characters.

Example:

Input: "Hello, my name is John"
Output: 5

这道题目就更加简单了,主要搞清楚两点,一个是开头和结尾的空格,使用trim函数处理,第二个是连续的空格,使用“ +”进行切分,但是内置函数方法效率较低,我这里提供三种方法,如下:

    //10%
    public static int countSegments(String s) {
        if(s == null || s.equals("") || s.trim().equals(""))
            return 0;
        String[] res = s.trim().split(" +");
        return res.length;
    }

    //28%
    public int countSegments1(String s) {
        int res=0;
        for(int i=0; i<s.length(); i++)
            if(s.charAt(i)!=' ' && (i==0 || s.charAt(i-1)==' '))
                res++;
        return res;
    }

    //63%
    public int countSegments2(String s) {
        int segs = 0;
        char[] chars = s.toCharArray();
        for(int i=0;i<chars.length;i++) {
            if(chars[i]!=' ') segs++;
            while(i<chars.length && chars[i]!=' ') i++;
        }
        return segs;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值