字符串相关

 注意本题最好用双指针方法来解决,因为涉及数组的两个方向,注意双指针可以同步移动,也可以根据条件来进行移动

class Solution {
    public void reverseString(char[] s) {
        if (s.length == 1 || s.length == 0) return;    
        for (int i = 0; i < s.length; ++i) {
            if (i <= s.length - i -1) {
                char temp = s[s.length -1- i];
                s[s.length -1- i] = s[i];
                s[i] = temp;
            } else break;
        }
    }
}

我原来的写法根据数组的重点位置来进行判断,在重点位置根据奇偶的情况会导致出现问题。最好还是不要用除以2来确定重点,通过i 和s.length - 1 - i来构造双指针,根据终止条件来限制for循环的此处,这样结果更准确。

class Solution {
    public void reverseString(char[] s) {
        int n = s.length;
        for (int left = 0, right = n - 1; left < right; ++left, --right) {
            char tmp = s[left];
            s[left] = s[right];
            s[right] = tmp;
        }
    }
}

 利用到上一题的基本方法,但是双指针遍历过程中,尾部指针的位置发生了变化。注意这种大区间里面选择小区间的行为。

class Solution {
    public String reverseStr(String s, int k) {
        //还是要利用双指针的方法,这里要注意for循环的递增是以2k为区间
        char[] ch = s.toCharArray();
        for (int i = 0; i < ch.length; i += 2*k) {
            int start = i;
            //尾部的选择来看数组的结尾序号和开始指针算出来的哪个小
            int end = Math.min(ch.length - 1, start + k -1);
            while (start < end) {
                char temp = ch[start];
                ch[start] = ch[end];
                ch[end] = temp;
                start++;
                end--;
            }
        }
        return new String(ch);
    }
}

利用异或运算来实现来个元素的交换,注意异或运算符号交换律以及结合律。过程可以参考链接

Java中异或运算实现两个整数的交换以及其功能函数实现_小小沸沸要加油的博客-CSDN博客 

//解法二(似乎更容易理解点)
//题目的意思其实概括为 每隔2k个反转前k个,尾数不够k个时候全部反转
class Solution {
    public String reverseStr(String s, int k) {
        char[] ch = s.toCharArray();
        for(int i = 0; i < ch.length; i += 2 * k){
            int start = i;
            //这里是判断尾数够不够k个来取决end指针的位置
            int end = Math.min(ch.length - 1, start + k - 1);
            //用异或运算反转 
            while(start < end){
                ch[start] ^= ch[end];
                ch[end] ^= ch[start];
                ch[start] ^= ch[end];
                start++;
                end--;
            }
        }
        return new String(ch);
    }
}

这里对字符串里面的字符的替换方法有很多

(1)利用String自带的api,replace(“”,“”)或者replaceAll(“”,“”) 

(2)利用字符串和数组的api,split()(返回字符串数组)和join(“”)的链式编程来进行。

(3)利用stringbuilder或者stringbffer来进行

class Solution {
    public String replaceSpace(String s) {
        char[] ch = s.toCharArray();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < ch.length; ++i) {
            if (ch[i] == ' ')  sb.append("%20");
            else sb.append(ch[i]);
        }
        return sb.toString();
    }
}

注意这里对字符串的处理办法,首先可以利用常见的api,要注意这些常见api的用法和返回值

class Solution {
    public String reverseWords(String s) {
        s = s.trim();//去掉头尾的字符串,注意不对原来的字符串进行改变
        //利用正则表达式来取得字符串里面不含空格的部分
        List<String> wordlist = Arrays.asList(s.split("\\s+"));
        Collections.reverse(wordlist);
        return String.join(" ",wordlist);
    }
}

参考答案解析中的一个思路,通过对字符串进行遍历,利用两个指针来进行单词字符串的选取。

这里要注意当最后一个位空格是,会使得word位“”,注意此时不要和res进行字符串的拼接。 

class Solution {
    public String reverseWords(String s) {
        //参考题目解析中的一个思路,利用for循环挨个取出其中的单词
        String res = "";
        for (int i =0; i < s.length();) {
            String word = "";
            //去掉开头的空格位置
            while (i < s.length() && s.charAt(i) == ' ') i++;
            int j = i;
            //让j读取到单词的结尾后的空格处
            while (j < s.length() && s.charAt(j) != ' ') j++;
            word = s.substring(i,j);
            //拼接单词,注意将新的单词放前面,原来的结果放在后面
            //注意没加一个单词就在前面加上一个空格,最后取子串的时候从第2个字符开始取就可以
            if (word != "") res = " " + word + res;
            //去除单词后面的空格
            // while (j < s.length() && s.charAt(j) == ' ') j++;
            i = j;
        }
        return res.substring(1);
    }
}

 

这里方法有三种,第一种是利用切片来进行处理,这是需要额外空间最少的,两个就可以

另外一个是利用stringbuilder来进行,对字符串进行遍历。

class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder res = new StringBuilder();
        for(int i = n; i < s.length(); i++)
            res.append(s.charAt(i));
        for(int i = 0; i < n; i++)
            res.append(s.charAt(i));
        return res.toString();
    }
}

作者:jyd
链接:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/solution/mian-shi-ti-58-ii-zuo-xuan-zhuan-zi-fu-chuan-qie-p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

注意这里可以通过一个取余操作来简化代码

class Solution {
    public String reverseLeftWords(String s, int n) {
        StringBuilder res = new StringBuilder();
        for(int i = n; i < n + s.length(); i++)
            res.append(s.charAt(i % s.length()));
        return res.toString();
    }
}

作者:jyd
链接:https://leetcode.cn/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/solution/mian-shi-ti-58-ii-zuo-xuan-zhuan-zi-fu-chuan-qie-p/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

这里要注意对字符串进行遍历,判断位置是查找串和目标串的第一个字符相等

这里注意if条件里面的判断条件i+n《m不要漏掉

class Solution {
    public int strStr(String haystack, String needle) {
        if (needle == null) return 0;
        int n = needle.length();
        int m = haystack.length();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < m;){
            //找到第一个字符
            while (i < m && haystack.charAt(i) != needle.charAt(0)) i++;
            if (i < m && i+n <= m && haystack.substring(i,i+n).equals(needle)) return i;
            else i++;
        }
        return -1;
    }
}
class Solution {
    public int strStr(String ss, String pp) {
        int n = ss.length(), m = pp.length();
        char[] s = ss.toCharArray(), p = pp.toCharArray();
        // 枚举原串的「发起点」
        for (int i = 0; i <= n - m; i++) {
            // 从原串的「发起点」和匹配串的「首位」开始,尝试匹配
            int a = i, b = 0;
            while (b < m && s[a] == p[b]) {
                a++;
                b++;
            }
            // 如果能够完全匹配,返回原串的「发起点」下标
            if (b == m) return i;
        }
        return -1;
    }
}

kmp算法的解法:详细对于kmp方法的介绍可以看代码随想录,核心关键是next数组的求取

class Solution {
    public int strStr(String ss, String pp) {
        if (pp == null) return 0;
        if (ss.length() < pp.length()) return -1;
        int[] next = new int[pp.length()];//创建模式字符串容量的数组
        getNext(next,pp);
        int j = 0;
        for (int i = 0; i < ss.length(); ++i) {
            while (j > 0 && ss.charAt(i) != pp.charAt(j)) j = next[j-1];
            if (ss.charAt(i) == pp.charAt(j)) j++;
            if (j == pp.length()) return i - pp.length() + 1;
        } 
        return -1;    
    }
    public void getNext(int[] next, String str) {
        int j = 0;
        next[0] = j;//代表字符串第一个字符的最大前后缀相等的长度
        //通过for循环来遍历整个字符串,确定每一个字符对应的next数组值
        for (int i = 1; i < str.length(); ++i) {
            while (j > 0 && str.charAt(i) != str.charAt(j)) j = next[j -1];
            if (str.charAt(i) == str.charAt(j)) j++;
            next[i] = j;
        }
    }
}

 注意getNext方法和利用next数组来确定回退位置,大体上是相同的,但是一个是比较相同的字符串,一个是比较文本串和模式串。

本题可以查看官方解法的第二个,利用string的indexOf()四个方法里面的一个

然后是学习代码随想录的kmp改进方法,利用最大长度的相等前后缀不包含的部分长度,对字符串总长度取余,模为0则表明可以重复,否则不可以。

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        if (s.equals("")) return false;

        int len = s.length();
        char[] chars = s.toCharArray();
        int[] next = new int[len];
        int j = 0;
        next[0] = j;
        // 构造 next 数组过程,j从0开始(空格),i从2开始
        for (int i = 1; i < len; i++) {
            // 匹配不成功,j回到前一位置 next 数组所对应的值
            while (j > 0 && chars[i] != chars[j]) j = next[j-1];
            // 匹配成功,j往后移
            if (chars[i] == chars[j]) j++;
            // 更新 next 数组的值
            next[i] = j;
        }

        // 最后判断是否是重复的子字符串,这里 next[len] 即代表next数组末尾的值
        if (next[len-1] > 0 && len % (len - next[len-1]) == 0) {
            return true;
        }
        return false;
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值