对于字符串的相关题目,主要分为两类
本文主要介绍字符串操作相关,包括反转,压缩,替换 等
字符串基本理论知识可参考:java字符串(String & StringBuilder)
字符串匹配可参考:leetcode字符串小结(下)
(1)熟悉字符串的操作
字符串的操作,有一定技巧性,并且还需要熟悉相关API的使用
比如String常用的有: 截取操作substring(int beginIndex, int endIndex)
;字符串转换为字符数组char[ ] toCharArray()
;替换 replace(char searchChar, char newChar)
等
StringBuilder中:反转操作 reverse()
;字符串连接 append()
;转换为String toString()
等
(2)双指针
与数组一样,双指针在字符串中同样作用很大(数组和字符串很多相似之处)
关于双指针的详细介绍,可以参见: 双指针。在很多想要暴力的场景下,不妨想想双指针!尤其是快慢指针和前后指针!
力扣链接 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)。只使用了常数空间来存放若干变量
力扣题目链接 lc541
题目描述:
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例:
输入:s = “abcdefg”, k = 2 输出:“bacdfeg”
输入:s = “abcd”, k = 2 输出:“bacd”
题目链接 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();
}
题目链接: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;
}
题目链接: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;
题目链接: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 static String reverseLeftWords(String s, int n) {
String src = s;
// 循环表示 n 次移位
for(int i=0;i<n;i++) {
// 获取首字母
char first = src.charAt(0);
// 通过subString截取后部分
String last = src.substring(1);
// 将 last和 first 拼接
src = last + first;
}
return src;
}
结果:
执行用时太长,pass
(看破本质一步到位法)
思路:
代码:
public String reverseLeftWords(String s, int n) {
return s.substring(n)+s.substring(0,n);
}
结果:时间复杂度大大提升了
Solution3: