剑指 Offer 05. 替换空格
题目描述
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
限制:
-
0
<
=
s
的
长
度
<
=
10000
0 <= s 的长度 <= 10000
0<=s的长度<=10000
解法一:StringBuilder
思路:
- 使用 StringBuilder sb 来存放 新结果;
- 若 s[i] 为空格,则将 “%20” 插入到 sb 中;
- 否则,则将 s[i] 插入 sb 中
class Solution {
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();
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
解法2:双指针
该方法在 C++ 语言中能使得空间复杂度将为 O ( 1 ) O(1) O(1),但是由于 Java 中 String 是不可变的,所以在 Java 中该方法空间复杂度仍为 O ( n ) O(n) O(n). (可以借鉴 双指针 思路)
思路:
- 统计 s 中 空格 个数 s p a c e s spaces spaces;
- 创建用于存放 新s 的数组
char[] arr = new char[n + 2 * spaces];
- 双指针
从后向前
遍历:- 若 s[i] 为空格,则将 arr[j] 向前分别添加 ‘0’、‘2’、’%’ (注意 逆序 );
- 否则,直接将 s[i] 赋给 arr[j]
class Solution {
public String replaceSpace(String s) {
int n = s.length();
int spaces = 0; // 空格个数
for (int i = 0; i < n; i++) {
if (s.charAt(i) == ' ') spaces++;
}
char[] arr = new char[n + 2 * spaces]; // 新的s
int newLen = arr.length;
int i = n - 1; // s
int j = newLen - 1; // 新 s
while (i >= 0) {
if (s.charAt(i) == ' ') {
// 替换空格为 “%20”,但要注意此时是 逆序
arr[j--] = '0';
arr[j--] = '2';
arr[j--] = '%';
} else {
arr[j--] = s.charAt(i);
}
i--;
}
return new String(arr);
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n) (Java 中 String 不可变,在 C++ 中可以降为 O ( 1 ) O(1) O(1))
剑指 Offer 58 - II. 左旋转字符串
题目描述
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
限制:
- 1 < = k < s . l e n g t h < = 10000 1 <= k < s.length <= 10000 1<=k<s.length<=10000
解法一:StringBuilder
思路:
- 使用 StringBuilder 保存新的 s
- 截取 s[n, len) 到 sb;
- 截取 s[0, n) 到 sb
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder sb = new StringBuilder();
// s[n, len)
for (int i = n; i < s.length(); i++) sb.append(s.charAt(i));
// s[0, n)
for (int i = 0; i < n; i++) sb.append(s.charAt(i));
return sb.toString();
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
双指针:局部反转 + 整体反转
思路:
- 局部反转:s[0, n - 1];
- 局部反转:s[n - 1, len - 1];
- 整体反转:s[0, len - 1].
class Solution {
public String reverseLeftWords(String s, int n) {
int len = s.length();
char[] arr = s.toCharArray();
// 局部反转
reverse(arr, 0, n - 1);
// System.out.println(Arrays.toString(arr));
reverse(arr, n, len - 1);
// 整体反转
reverse(arr, 0, len - 1);
return new String(arr);
}
// 反转 s[left, right] 中字符
public void reverse(char[] arr, int left, int right) {
// 双指针
while (left < right) {
char temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
}
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n) (如果使用 C++、或者题目给的是 char[],则可以将 空间复杂度降为 O ( 1 ) O(1) O(1))