leetcode字符串(上)——字符串操作

前言

对于字符串的相关题目,主要分为两类

  • 字符串操作
  • 字符串匹配

本文主要介绍字符串操作相关,包括反转,压缩,替换 等

字符串基本理论知识可参考:java字符串(String & StringBuilder)
字符串匹配可参考:leetcode字符串小结(下)

题目&推荐

1.经验+技巧

(1)熟悉字符串的操作
字符串的操作,有一定技巧性,并且还需要熟悉相关API的使用

比如String常用的方法有:

  • 截取操作substring(int beginIndex, int endIndex)
  • 字符串转换为字符数组char[ ] toCharArray()
  • 替换 replace(char searchChar, char newChar)

StringBuilder中方法:

  • 反转操作 reverse()
  • 字符串连接 append()
  • 转换为String toString();
  • 索引处赋值:setCharAt(int index,char chs)

(2)双指针
与数组一样,双指针在字符串中同样作用很大(数组和字符串很多相似之处)

关于双指针的详细介绍,可以参见: 双指针。在很多想要暴力的场景下,不妨想想双指针!尤其是快慢指针和前后指针!

2.题目列表

开撸

1.lc344 反转字符串

力扣链接 lc344

题目描述:

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

示例:

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

如果题目没有要求原地修改,就是一般的反转,那就很简单:

public static String reverseString(char[] s)
 {
        char[] newS = new char[s.length];
        for(int i=0;i<s.length;i++)
        {
            newS[i] = s.[s.length-i-1];
        }
        return newS;
}

言归正传,如果是原地修改的话,那可以使用双指针

public void reverseString(char[] s) {
        /*
        定义两个指针,一个指向前面,一个指向后面
        两个指针同时向中间移动,并交换元素。
        */
        int p = 0;
        int q = s.length-1;

        while(p<q)
        {
            char tmp = s[p];
            s[p] = s[q];
            s[q] = tmp;
            p++;
            q--;
        }
  }

时间复杂度:O(N),其中 N 为字符数组的长度。一共执行了 N/2 次的交换。
空间复杂度:O(1)。只使用了常数空间来存放若干变量

2.lc541 反转字符串 II

力扣题目链接 lc541

题目描述:

给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。

示例:

输入:s = “abcdefg”, k = 2 输出:“bacdfeg”
输入:s = “abcd”, k = 2 输出:“bacd”

3.lc151 反转字符串中的单词

lc151链接

题目描述

给你一个字符串 s ,请你反转字符串中 单词 的顺序。如有多余空格需要去除

示例:

输入:s = " hello world "  输出:“world hello”

Solution:
分三步走,先去除多余空格在,再反转整个字符串最后反转每个单词

class Solution {
    public String reverseWords(String s) {
        // 去除多余空格
        StringBuilder sb = removeSpace(s);
        // 反转这个字符串
        reverse(sb,0,sb.length()-1);
        // 反转每个单词
        reverseEachWord(sb);

        return sb.toString();
    }
    public StringBuilder removeSpace(String s)
    {
        StringBuilder sb = new StringBuilder();

        int start =0,end = s.length()-1;
        // 去除前导空格
        while(s.charAt(start)==' ') start++;
        // 去除尾随空格
        while(s.charAt(end)==' ') end--;

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

            start++;
        }

        return sb;
    }
    public void reverse(StringBuilder sb,int l,int r)
    {
        while(l<r)
        {
            // 双指针交换
            char chs = sb.charAt(l);
            sb.setCharAt(l,sb.charAt(r));
            sb.setCharAt(r,chs);
            l++;
            r--;
        }
    }
    public void reverseEachWord(StringBuilder sb)
    {
        int start =0, end=1;
        int n = sb.length();
        while(start<n)
        {
            // 先找到第一个单词结束处
            while(end<n && sb.charAt(end)!=' ')
                end++;
            // 获得单词的首尾索引,然后反转
            reverse(sb,start,end-1);
            // 继续下一个单词
            start = end+1;
            end = start+1;
        } 
    }
}

4.剑指Offer58-II.左旋转字符串

题目链接:offer58 左旋转字符串

题目描述

字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。

示例:

输入: s = “abcdefg”, k = 2   输出: “cdefgab”

Solution 1:
每次移动一个字符

class Solution {
    public String reverseLeftWords(String s, int n) { 
        char[] chs = s.toCharArray();
        for(int j=0;j<n;j++) {
            char tmp = chs[0];
            for (int i = 0; i < s.length() - 1; i++)
                chs[i] = chs[i + 1];
            chs[s.length() - 1] = tmp;
        }
        String t = new String(chs);
        return t;

    }
}

solution 2——切片法:
(看破本质一步到位法)

代码:

public String reverseLeftWords(String s, int n) {
       return s.substring(n)+s.substring(0,n);
    }

结果:时间复杂度大大提升了

Solution3:
与上一题相似的思路:先反转前半段,再反转后半段,最后反转整个字符串

5.剑指Offer 05替换空格

题目链接 offer05

描述:

请实现一个函数,把字符串 s 中的每个空格替换成"%20"

示例

输入:s = “We are happy.”
输出:“We%20are%20happy.”

Solution:
善于运用StringBuilder

 public String replaceSpace(String s) {

     StringBuilder sb = new StringBuilder();

     for(int i=0;i<s.length();i++)
     {
         if(s.charAt(i)==' ')
            sb.append("%20");

         else
            sb.append(s.charAt(i));
     }
     return sb.toString();
 }

6.lc443 压缩字符串

题目链接:lc443

题目描述

给你一个字符数组 chars ,请使用下述算法压缩

示例:

输入:chars = [“a”,“a”,“b”,“b”,“c”,“c”,“c”]
输出:返回 6 ,输入数组的前 6 个字符应该是:[“a”,“2”,“b”,“2”,“c”,“3”]

solution

public int compress(char[] chars) {
        // 定义快慢指针,和需要插入的索引index
        int slow=0,fast,index=0;

        while(slow<chars.length)
        {
            fast = slow;
            // 1.如果快指针指向的元素与慢指针相同,快指针一直移动
            while(fast<chars.length && chars[fast]==chars[slow])
               fast++;

            // 2.快指针开始遇到不重复的
            chars[index++] = chars[slow]; //开始原地修改
            int cnt = fast-slow;  // 计算重复的长度
            // 将长度转成字符串再取各个位
            if(cnt>1)
            {
                String cntStr = Integer.toString(cnt);
                for(int i=0;i<cntStr.length();i++)
                   chars[index++] = cntStr.charAt(i);
            }
            // 慢指针更新
            slow = fast;
        }
        return index;
    }

7.lc14 最长公共前缀

题目链接:lc14

题目描述

编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串

示例:

输入:strs = [“flower”,“flow”,“flight”] ; 输出:“fl”

solution :

public String longestCommonPrefix(String[] strs) {
        // 横向扫描,挨个比较
        
        // 先假设最长前缀就是第一个字符串
        String ans = strs[0];
        
        //将第一个分别与后面的字符串进行前缀比较
        for(int i=1;i<strs.length;i++)
        {
            int j=0;
            while(j<Math.min(ans.length(),strs[i].length()) && strs[i].charAt(j)==ans.charAt(j) )
               j++;

            ans = ans.substring(0,j); // 开始截取
            if(ans=="") return ""; // 如果此时ans为空,直接返回
        }
        return ans;
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值