算法训练营Day8

#Java #字符串

开源学习资料

Feeling and experiences:

 反转字符串:力扣题目链接

该题目出奇的简单,写完之后一度反复看题目,是否是有遗漏的条件。 

再扩展一下,做这类题的时候,首先想到的就是相向双指针进行首尾交换。同样,在Java的API的Arrays类中有reverse方法,可以使得数组或者是集合,让内部元素进行反转。

 代码如下,简单的while循环:

class Solution {
    public void reverseString(char[] s) {
    //把给定数组中的元素反转过来
    //双指针交换?
    int first = 0;
    int end = s.length-1;
    //首尾交换
    while(first<end){
        char temp = s[first];
       s[first] = s[end];
       s[end--] = temp;
       first++;  
    }

    }
    
}

反转字符串II :力扣题目链接

本题在上一题的基础上多了几个条件:

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。

  • 如果剩余字符少于 k 个,则将剩余字符全部反转。
  • 如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

其本质上还是需要交换,所以我的思路是这样的:

虽然有很多判断条件,但是最主要的执行的还是交换,所以可以写一个交换的方法。

之后判断条件,满足就交换。

class Solution {
    public String reverseStr(String s, int k) {
        //先把字符串放到数组中,这样以便于操作
        char[] res = s.toCharArray();
    //本质上也是交换
    //多了附加的条件,还是要遍历数组进行处理
    for(int i =0;i<res.length;i+=2*k){
    //如果剩余字符少于 k 个,则将剩余字符全部反转。
    //那么到达k的时候就和后面k个进行交换,当然要确保后面还有k个
    if (i + k <= res.length) {
                reverse(res, i, i + k -1);
                //没有continue就会一直交换
                continue;
            }
             // 当 剩余字符少于了k个,就将剩余字符全部反转
            reverse(res, i, res.length - 1);
    }
    
    //将数组变成字符串返回
    return new String(res);
}


    //先写一个交换方法
    public void reverse(char[] charArray,int i,int j){
         for (; i < j; i++, j--) {
           char temp = charArray[i];
           charArray[i] = charArray[j];
           charArray[j] = temp;
        }
    }
        
    }

Java写这道题就麻烦一点,因为不能直接对字符串进行操作,先转数组。

我写出来发现和代码随想录的解法三是一样的。

前两种解法就更麻烦了,要创建StringBuffer对象,在进行处理。

char * reverseStr(char * s, int k){
    int len = strlen(s);

    for (int i = 0; i < len; i += (2 * k)) {
        
        k = i + k > len ? len - i : k;

        int left = i;
        int right = i + k - 1;
        while (left < right) {
            char temp = s[left];
            s[left++] = s[right];
            s[right--] = temp;
        }
    }

    return s;
}

用C/C++就简单得多。

 

替换数字 :卡码网题目链接

给定一个字符串 s,它包含小写字母和数字字符,请编写一个函数,将字符串中的字母字符保持不变,而将每个数字字符替换为number。 例如,对于输入字符串 "a1b2c3",函数应该将其转换为 "anumberbnumbercnumber"。

关键就在于找到数字,把数字替换了即可。

在Java中直接使用Character.isDigit(),就能找到数字。

没有什么难度,但是要创建额外空间,这也是Java一个不好的地方。

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        //读取数据
        Scanner in = new Scanner(System.in);
        String s = in.next();
        //创建StringBuilder对象
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < s.length(); i++) {
            //判断是否为数字
            if (Character.isDigit(s.charAt(i))) {
                res.append("number");
            }else res.append(s.charAt(i));
        }
        System.out.println(res);
    }
}

 

翻转字符串里的单词:力扣题目链接 

该题目我通过画图模拟,整理好了思路:

利用双指针(end指针,和index指针),index指针先记录end指针的出发位置,end从末尾出发(前提是末尾不是空格),如果末尾存在空格,则遍历到有字母

之后一直循环遍历,当end指针指到空格,则利用subString(end+1,index+1) 因为是左闭右开!

 官方代码与解释如下:

class Solution {
    public String reverseWords(String s) {
        StringBuilder sb = trimSpaces(s);

        // 翻转字符串
        reverse(sb, 0, sb.length() - 1);

        // 翻转每个单词
        reverseEachWord(sb);

        return sb.toString();
    }

    public StringBuilder trimSpaces(String s) {
        int left = 0, right = s.length() - 1;
        // 去掉字符串开头的空白字符
        while (left <= right && s.charAt(left) == ' ') {
            ++left;
        }

        // 去掉字符串末尾的空白字符
        while (left <= right && s.charAt(right) == ' ') {
            --right;
        }

        // 将字符串间多余的空白字符去除
        StringBuilder sb = new StringBuilder();
        while (left <= right) {
            char c = s.charAt(left);

            if (c != ' ') {
                sb.append(c);
            } else if (sb.charAt(sb.length() - 1) != ' ') {
                sb.append(c);
            }

            ++left;
        }
        return sb;
    }

    public void reverse(StringBuilder sb, int left, int right) {
        while (left < right) {
            char tmp = sb.charAt(left);
            sb.setCharAt(left++, sb.charAt(right));
            sb.setCharAt(right--, tmp);
        }
    }

    public void reverseEachWord(StringBuilder sb) {
        int n = sb.length();
        int start = 0, end = 0;

        while (start < n) {
            // 循环至单词的末尾
            while (end < n && sb.charAt(end) != ' ') {
                ++end;
            }
            // 翻转单词
            reverse(sb, start, end - 1);
            // 更新start,去找下一个单词
            start = end + 1;
            ++end;
        }
    }
}

但在力扣中,因为要求空间复杂度为O(1);

这也加大了题的难度。 

双指针的方法如下:

class Solution {
    public String reverseWords(String s) {
        int n = s.length();
        StringBuilder ans = new StringBuilder();
        for (int i = n - 1; i > -1; --i) {
            if (s.charAt(i) == ' ') continue;
            int j = i;
            while (j > 0 && s.charAt(j - 1) != ' ') {
                --j;
            }
            ans.append(s.substring(j, i + 1)).append(" ");
            i = j;
        }
        return ans.deleteCharAt(ans.length() - 1).toString();
    }
    }

第一遍写的代码,存在错误:

class Solution {
    public String reverseWords(String s) {
    //先创建一个StringBuilder 用来存放结果
    StringBuilder sb = new StringBuilder();
    //用双指针
    int end = s.length()-1;
    int index = end;
    if(s.charAt(end) == ' '){
        end--;
        index = end;
    }
    //从这个if语句中出来,就能得到index和end指向的是字母,而不是空格
    
    //循环遍历s
    while(end>=0){
       
    while(s.charAt(end) != ' '&& end>0){
        //一直遍历下去,直到找到空格为止
          end--;
    }
    //记录之后,就要把它加入到sb中
    if(index!=end && s.charAt(end+1) != ' '){
    sb.append(s.substring(end+1,index+1)+" "); //因为是左闭右开
    //用来记录end的出发位置,之后好寻找到这个单词
    }
    index = end;
    //退出第一个循环,说明找到了空格,那么当前end指针指到就是空格
     end--;

    }
    //这样添加之后,会导致结果最后多一个“ ” 所以要去掉
    if(sb.charAt(sb.length()-1) == ' '){
        sb.deleteCharAt(sb.length()-1);
    }
    return sb.toString();
}
}

该代码存在错误,第一遍写的时候的思路,在此记录一下。 

右旋字符串:卡码网题目链接

字符串的右旋转操作是把字符串尾部的若干个字符转移到字符串的前面。给定一个字符串 s 和一个正整数 k,请编写一个函数,将字符串中的后面 k 个字符移到字符串的前面,实现字符串的右旋转操作。 

例如,对于输入字符串 "abcdefg" 和整数 2,函数应该将其转换为 "fgabcde"。

 综合上述的题,我的思路是,从后往前遍历,把倒数k个数取出来和剩下的拼接。

 

 

在idea中测试了一下,看来这种方法是行得通的。

代码如下:

package Day1;

import java.util.Scanner;

public class Practise01 {
    public static void main(String[] args) {
       Scanner scanner = new Scanner(System.in);
       String str = scanner.nextLine();
       int k = scanner.nextInt();
       StringBuilder sb  = new StringBuilder();
        int index = str.length()-1;
        int count = 0;
        while(count != k){
            sb.append(str.charAt(index));
            count++;
            index--;
        }
        for(int i =0;i<str.length()-k;i++) {
            sb.append(str.charAt(i));
        }
        System.out.println(sb.toString());
    }

}

 

今日的练习题目较为简单,主要是能熟练地运用语言的API。

不乱于心,不困于情,不畏将来,不念过往

如此,

安好~ 

Fighting!

 

 

 

 

 

 

 

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值