344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 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 码表中的可打印字符
教程:https://programmercarl.com/0344.%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2.html
视频:https://www.bilibili.com/video/BV1fV4y17748/
方法一:
思路:首尾进行交换。
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while(l < r){
char temp = s[l];
s[l] = s[r];
s[r] = temp;
l++;
r--;
}
}
}
541. 反转字符串 II
给定一个字符串 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
教程:https://programmercarl.com/0541.%E5%8F%8D%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2II.html
视频:https://www.bilibili.com/video/BV1dT411j7NN/
方法一:
思路:
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( n ) O(n) O(n)
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);
}
}
class Solution {
public String reverseStr(String s, int k) {
char[] s1=s.toCharArray();
int left = 0;
int right = s.length();
while(left<right){
int i =left + k;
if(i<right){
// 创建一个新的字符数组
char[] kArray = new char[k];
// 将切片复制到新的字符数组中
int start=left;
for (int j = start; j < i; j++) {
kArray[i - start] = s1[i];
}
reverseString(kArray);
}
left=i;
}
String s2 = s1.toString();
return s2;
}
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while(l < r){
char temp = s[l];
s[l] = s[r];
s[r] = temp;
l++;
r--;
}
}
}
LCR 122. 路径加密
假定一段路径记作字符串 path
,其中以 “.
” 作为分隔符。现需将路径加密,加密方法为将 path
中的分隔符替换为空格 "
",请返回加密后的字符串。
示例 1:
输入:path = "a.aef.qerf.bb"
输出:"a aef qerf bb"
限制:
0 <= path.length <= 10000
教程:https://programmercarl.com/%E5%89%91%E6%8C%87Offer05.%E6%9B%BF%E6%8D%A2%E7%A9%BA%E6%A0%BC.html
方法一:调用函数replace
第一反应是java里面的函数replace,hhh。对于练习算法而言,这个方法不提倡。
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( 1 ) O(1) O(1)
class Solution {
public String pathEncryption(String path) {
return path.replace('.',' ');
}
}
方法二:用StringBuilder
**思路:**不太了解Java数据类型的,根本想不到用这个
整体思路就是新建一个变量StringBuilder存结果,遍历当前String,往StringBuilder里存。
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( n ) O(n) O(n)
class Solution {
public String pathEncryption(String path) {
if (path == null) {
return null;
}
//选用 StringBuilder 单线程使用,比较快,选不选都行
StringBuilder sb = new StringBuilder();
//使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制
for (int i = 0; i < path.length(); i++) {
//s.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型
//if (" ".equals(String.valueOf(s.charAt(i)))){}
if (path.charAt(i) == '.') {
sb.append(' ');
} else {
sb.append(path.charAt(i));
}
}
return sb.toString();
}
}
在Java语言中,StringBuilder是一个类,属于java.lang包。它用于创建和操作可变的字符串对象,与String对象不同,StringBuilder对象的内容可以被修改,而不需要创建新的对象。
151. 反转字符串中的单词
给你一个字符串 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
中 至少存在一个 单词
视频:https://www.bilibili.com/video/BV1uT41177fX
方法一:调用函数
思路:
很朴素的想法
- 用split切成数组,用正则化匹配一个或多个空格;
- 将数组逆置一下,考虑首尾交换
- 然后遍历一下,每个元素加上空格
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( n ) O(n) O(n)
class Solution {
public String reverseWords(String s) {
String[] s2 = s.split("\\s+");//使用正则化:匹配一个或多个空格
int left = 0;
int right = s2.length - 1;
while (left < right) {
String temp = s2[left];
s2[left] = s2[right];
s2[right] = temp;
left++;
right--;
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s2.length; i++) {
sb.append(s2[i]).append(" "); // 修改连接符为空格
}
return sb.toString().trim(); //去除末尾空格
}
}
正则表达式中的 \\s+
表示匹配一个或多个空白字符。
\\s
: 表示匹配任何空白字符,包括空格、制表符、换行符等。+
: 表示匹配前面的元素(也就是\\s
)一次或多次。
str.trim()
去除String类型str变量首尾空格
方法二:
思路:参考代码随想录官网,比上面一个快
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( n ) O(n) O(n)
class Solution {
public String reverseWords(String s) {
// System.out.println("ReverseWords.reverseWords2() called with: s = [" + s + "]");
// 1.去除首尾以及中间多余空格
StringBuilder sb = removeSpace(s);
// 2.反转整个字符串
reverseString(sb, 0, sb.length() - 1);
// 3.反转各个单词
reverseEachWord(sb);
return sb.toString();
}
private StringBuilder removeSpace(String s) {
// System.out.println("ReverseWords.removeSpace() called with: s = [" + 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++;
}
// System.out.println("ReverseWords.removeSpace returned: sb = [" + sb + "]");
return sb;
}
/**
* 反转字符串指定区间[start, end]的字符
*/
public void reverseString(StringBuilder sb, int start, int end) {
// System.out.println("ReverseWords.reverseString() called with: sb = [" + sb + "], start = [" + start + "], end = [" + end + "]");
while (start < end) {
char temp = sb.charAt(start);
sb.setCharAt(start, sb.charAt(end));
sb.setCharAt(end, temp);
start++;
end--;
}
// System.out.println("ReverseWords.reverseString returned: sb = [" + sb + "]");
}
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;
}
}
}
LCR 182. 动态口令
某公司门禁密码使用动态口令技术。初始密码为字符串 password
,密码更新均遵循以下步骤:
- 设定一个正整数目标值
target
- 将
password
前target
个字符按原顺序移动至字符串末尾
请返回更新后的密码字符串。
示例 1:
输入: password = "s3cur1tyC0d3", target = 4
输出: "r1tyC0d3s3cu"
示例 2:
输入: password = "lrloseumgh", target = 6
输出: "umghlrlose"
提示:
1 <= target < password.length <= 10000
方法一:两次for循环
思路:两次for循环。定义一个StringBuilder bd存结果。
第一次循环,将target后的数据存入;
第一次循环,将target前的数据存入;最后返回。
复杂度分析:
-
时间复杂度: O ( n ) O(n) O(n)
-
空间复杂度: O ( n ) O(n) O(n)
class Solution {
public String dynamicPassword(String password, int target) {
StringBuilder bd = new StringBuilder();
for(int i =target;i< password.length();i++){
bd.append(password.charAt(i));
}
for(int i=0;i<target;i++){
bd.append(password.charAt(i));
}
return bd.toString();
}
}
方法二:
思路:
复杂度分析:
-
时间复杂度: O ( l e n ) O(len) O(len)
-
空间复杂度: O ( l e n ) O(len) O(len),len为密码字符串的长度。
class Solution {
public String dynamicPassword(String s, int n) {
int len=s.length();
StringBuilder sb=new StringBuilder(s);
reverseString(sb,0,n-1);
reverseString(sb,n,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--;
}
}
}