【代码随想录刷题】Day08 字符串

在这里插入图片描述


344.反转字符串
541.反转字符串II
【剑指Offer05】替换空格 LCR 122. 路径加密
151.反转字符串中的单词
【剑指Offer】LCR182.动态口令

1.【344】反转字符串

1.1 题目描述

编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。

不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。

示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]

示例 2:
输入:s = [“H”,“a”,“n”,“n”,“a”,“h”]
输出:[“h”,“a”,“n”,“n”,“a”,“H”]

提示:

  • 1 <= s.length <= 105
  • s[i] 都是 ASCII 码表中的可打印字符

1.2 解题思路

建议:不要使用库函数

此题和206.反转链表类似,可以使用双指针法。对于字符串的反转,比链表简单一些。因为字符串也是一种数组,所以在内存中是连续分布的。

swapa()交换函数有两种实现方式:

1.常见的交换数值,使用临时变量temp

int tmp = s[i];
s[i] = s[j];
s[j] = tmp;

2.通过位运算

s[i] ^= s[j];//构造a^b的结果,放在a中
s[j] ^= s[i];//将a^b的结果再^b,存入b中,b=a,a=a^b
s[i] ^= s[j];//a^b的结果再^a,存入a中,b=a,a=b完成交换

1.3 java代码实现

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
class Solution {
    public void reverseString(char[] s) {
        //使用temp来交换
        /*int left=0;
        int right=s.length-1;
        while (left<right){
            char temp=s[left];
            s[left]=s[right];
            s[right]=temp;

            left++;
            right--;*/

        //使用位运算来实现交换操作
        int left=0;
        int right=s.length-1;
        while (left<right){
            s[left] ^= s[right];//构造a^b的结果,放在a中
            s[right] ^= s[left];//将a^b的结果再^b,存入b中,b=a,a=a^b
            s[left] ^= s[right];//a^b的结果再^a,存入a中,b=a,a=b完成交换

            left++;
            right--;
        }

    }
}

2.【541】反转字符串II

2.1 题目描述

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

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

示例 1:
输入:s = “abcdefg”, k = 2
输出:“bacdfeg”

示例 2:
输入:s = “abcd”, k = 2
输出:“bacd”

提示:

  • 1 <= s.length <= 104
  • s 仅由小写英文组成
  • 1 <= k <= 104

2.2 解题思路

当需要固定规律一段一段的去处理字符串的时候,要想想在for循环的表达上做做文章

在遍历字符串的过程中,只要让i+=2ki每次移动2k就可以了,然后判断是否需要有反转的区间

2.3 java代码实现

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
class Solution {
    public String reverseStr(String s, int k) {
        //解法一 :
       /* char[] ch=s.toCharArray();
        //1.每隔2k个字符的前k个字符进行反转
        for (int i=0;i<ch.length;i+=2*k){
            //2.如果剩余字符小于2k,但大于或等于k个,则反转前k个字符
            if (i+k <=ch.length){
                reverse(ch,i,i+k-1);
                continue;
            }
            //3.剩余字符小于k个,则将剩余字符全部反转
            reverse(ch,i,ch.length-1);
        }
        return new String(ch);*/
    }
    //定义反转函数
    public void reverse(char[] ch,int i,int j){
        for (;i<j;i++,j--){
            char temp=ch[i];
            ch[i]=ch[j];
            ch[j]=temp;
        }
    }
}
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){
                char temp=ch[start];
                ch[start]=ch[end];
                ch[end]=temp;

                start++;
                end--;
            }
        }
        return new String(ch);
    }
}

3.【剑指Offer05】替换空格

3.1 题目描述

假定一段路径记作字符串 path,其中以 “.” 作为分隔符。现需将路径加密,加密方法为将 path 中的分隔符替换为空格 " ",请返回加密后的字符串。

示例 1:
输入:path = “a.aef.qerf.bb”
输出:“a aef qerf bb”

3.2 解题思路

使用一个新的对象,复制str,复制的过程对其判断,是分隔符.则替换为空格" ",否则直接复制,类似于数组复制

此题的原题是将字符串s中的空格替换成"%20"

原题的解题思路:双指针法
首先扩充数组到每个空格替换成"%20"之后的大小。然后从后向前替换空格。
其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。

这么做的好处:

  • 不用申请新数组。
  • 从后向前填充元素,避免了从前向后填充元素时,每次添加元素都要将添加元素之后的所有元素向后移动的问题。

3.3 java代码实现

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
class Solution {
    public String pathEncryption(String path) {
        //使用一个新的对象,复制str,复制的过程对其判断,是分隔符.则替换为空格" ",否则直接复制,类似于数组复制
        if (path==null){
            return null;
        }

        //选用StringBuilder   单线程使用,比较快
        StringBuilder sb=new StringBuilder();
        //使用sb逐个复制path,碰到分隔符.则替换为空格" ",否则直接复制
        for (int i=0;i<path.length();i++){
            //path.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型
            if (path.charAt(i)=='.'){
                sb.append(" ");
            }else {
                sb.append(path.charAt(i));
            }
        }
        return sb.toString();
        
        

    }
}

4.【151】反转字符串中的单词

4.1 题目描述

给你一个字符串 s ,请你反转字符串中 单词 的顺序。

单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。

返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。

注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。

示例 1:
输入:s = “the sky is blue”
输出:“blue is sky the”

示例 2:
输入:s = " hello world "
输出:“world hello”
解释:反转后的字符串中不能存在前导空格和尾随空格。

示例 3:
输入:s = “a good example”
输出:“example good a”
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。

提示:

  • 1 <= s.length <= 104
  • s 包含英文大小写字母、数字和空格 ’ ’
  • s 中 至少存在一个 单词

4.2 解题思路

1.移除多余空格:使用双指针法来移除 和27.移除元素的逻辑是一样的。
2.将整个字符串反转 :参考344.反转字符串
541.反转字符串II
3.将每个单词反转

4.3 java代码实现

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)

使用StringBuilder实现

class Solution {
    public String reverseWords(String s) {
        /**
         * 不使用Java内置方法实现
        
         * 1.去除收尾以及中间多余空格
         * 2.反转整个字符串
         * 3.反转各个单词
         */

        StringBuilder sb=removeSpace(s);
        reverseString(sb,0,sb.length()-1);
        reverseEachWord(sb);
        return sb.toString();


    }

    //去除首尾以及中间多余空格
    private StringBuilder removeSpace(String s){
        int start=0;
        int end=s.length()-1;
        while (s.charAt(start)==' ')
            start++;
        while (s.charAt(end)==' ')
            end--;

        StringBuilder sb=new StringBuilder();
        while (start<=end){
            char c=s.charAt(start);
            if (c!=' ' || sb.charAt(sb.length()-1)!=' '){
                sb.append(c);
            }
            start++;
        }
        return sb;
    }

    //反转字符串指定区间[start,end]的字符
    public void reverseString(StringBuilder sb,int start,int end){
        while (start<end){
            char temp=sb.charAt(start);
            sb.setCharAt(start,sb.charAt(end));
            sb.setCharAt(end,temp);
            start++;
            end--;
        }
    }

    //反转每个单词
    private void reverseEachWord(StringBuilder sb){
        int start=0;
        int end=1;
        int n=sb.length();

        while (start < n) {
            while (end<n && sb.charAt(end)!=' '){
                end++;
            }
            reverseString(sb,start,end-1);
            start=end+1;
            end=start+1;
        }
    }
}

用 char[] 来实现 String 的 removeExtraSpaces,reverse 操作

class Solution {
    public String reverseWords(String s) {
       
        char[] chars = s.toCharArray();
        //1.去除首尾以及中间多余空格
        chars = removeExtraSpaces(chars);
        //2.整个字符串反转
        reverse(chars, 0, chars.length - 1);
        //3.单词反转
        reverseEachWord(chars);
        return new String(chars);


    }
    
    //去除多余的空格
    public static char[] removeExtraSpaces(char[] chars){
        int slow=0;
        for (int fast=0;fast<chars.length;fast++){
            //先用fast移除所有空格
            if (chars[fast]!=' '){
                //再用slow加空格。除第一个单词外,单词末尾要加空格
                if (slow!=0){
                    chars[slow]=' ';
                    slow++;
                }
                //fast指针遇到空格或者遍历到字符串末尾,就证明遍历完一个单词了
                while (fast<chars.length && chars[fast] !=' '){
                    chars[slow]=chars[fast];
                    fast++;
                    slow++;
                }


            }
        }
        //相当于C++里面的resize()
        char[] newChars=new char[slow];
        System.arraycopy(chars,0,newChars,0,slow);
        return newChars;
    }
    //反转整个字符串  双指针实现
    public static void reverse(char[] chars,int left,int right){
        if (right>=chars.length){
            System.out.println("set a wrong right");
            return;
        }
        while (left<right){
            char temp=chars[left];
            chars[left]=chars[right];
            chars[right]=temp;
            left++;
            right--;
        }
    }

    //反转每个单词
    public void reverseEachWord(char[] chars) {
        int start = 0;
        //end <= s.length() 这里的 = ,是为了让 end 永远指向单词末尾后一个位置,这样 reverse 的实参更好设置
        for (int end = 0; end <= chars.length; end++) {
            // end 每次到单词末尾后的空格或串尾,开始反转单词
            if (end == chars.length || chars[end] == ' ') {
                reverse(chars, start, end - 1);
                start = end + 1;
            }
        }
    }
}

5.【剑指Offer】LCR182.动态口令

5.1 题目描述

某公司门禁密码使用动态口令技术。初始密码为字符串 password,密码更新均遵循以下步骤:

  • 设定一个正整数目标值 target
  • 将 password 前 target 个字符按原顺序移动至字符串末尾
    请返回更新后的密码字符串。

示例 1:
输入: password = “s3cur1tyC0d3”, target = 4
输出: “r1tyC0d3s3cu”

示例 2:
输入: password = “lrloseumgh”, target = 6
输出: “umghlrlose”

5.2 解题思路

5.3 java代码实现

class Solution {
    public String dynamicPassword(String password, int target) {
        int len=password.length();
        StringBuilder sb=new StringBuilder(password);
        reverseString(sb,0,target-1);
        reverseString(sb,target,len-1);
        return sb.reverse().toString();
    }
    public void reverseString(StringBuilder sb,int start,int end){
        while (start<end){
            char temp=sb.charAt(start);
            sb.setCharAt(start,sb.charAt(end));
            sb.setCharAt(end,temp);
            start++;
            end--;
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值