链接:Loading Question… - 力扣(LeetCode)
字符串长度 / 2
奇数偶数没有区别class Solution {
public void reverseString(char[] s) {
int len = s.length;
for(int l = 0, r = len - 1; l < len/2; l++, r--){
char temp = s[l];
s[l] = s[r];
s[r] = temp;
}
}
}
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--;
}
}
}
时间复杂度:O(N)
两个指针一个从头往后,一个从后往前,直到他们相遇,总共会把长度为N的字符数组全部遍历一遍,因此时间复杂度为O(N)
空间复杂度:O(1)
原地修改的字符数组,没有占用和创建其他空间,只有两个常数级的指针
题目:Loading Question… - 力扣(LeetCode)
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
// 每隔 2k 个字符的前 k 个字符进行反转
for (int i = 0; i < ch.length; i += 2 * k) {
if (i + k <= ch.length) {
// 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
reverse(ch, i, i + k - 1);
continue;
}
// 剩余字符少于 k 个,则将剩余字符全部反转
reverse(ch, i, ch.length - 1);
}
return new String(ch);
}
public void reverse(char[] ch, int l, int r){
while (l < r){
char temp = ch[l];
ch[l] = ch[r];
ch[r] = temp;
l++;
r--;
}
}
}
时间复杂度:O(N)
空间复杂度:O(N)
题目:剑指 Offer 05. 替换空格 - 力扣(LeetCode)
如果想把这道题目做到极致,就不要只用额外的辅助空间了!使用双指针法,从后向前的替换空格,过程如下:
"%20"
之后的大小right
指向新数组末尾,left
指向旧数组末尾left
,结束条件为:left ≥0
left
的元素替换right
位置上的元素right
位置替换成"%20"
,right
移动三位,left
移动一位从前向后填充就是O(n^2)的算法了,因为每次添加元素都要将添加元素之后的所有元素向后移动。其实很多数组填充类的问题,都可以先预先给数组扩容带填充后的大小,然后在从后向前进行操作。
这么做有两个好处:
class Solution {
public String replaceSpace(String s) {
if(s == null || s.length() == 0){
return s;
}
// 扩充空间
StringBuilder str = new StringBuilder();
for(int i = 0; i < s.length(); i++){
if(s.charAt(i) == ' '){
str.append(" ");
}
}
// 没有空格直接返回
if(str.length() == 0){
return s;
}
// 处理空格
int left = s.length() - 1;
s += str.toString();
int right = s.length() - 1;
char[] chars = s.toCharArray();
while (left >= 0){
// right 左移两位
if(s.charAt(left) == ' '){
chars[right--] = '0';
chars[right--] = '2';
chars[right] = '%';
}else{
chars[right] = chars[left];
}
left--;
right--;
}
return new String(chars);
}
}
时间复杂度:O(N)
空间复杂度:O(N)
题目:151. 反转字符串中的单词 - 力扣(LeetCode)
这道题目可以说是综合考察了字符串的多种操作。
所以这里我还是提高一下本题的难度:不要使用辅助空间,空间复杂度要求为O(1)。
我们将整个字符串都反转过来,那么单词的顺序指定是倒序了,只不过单词本身也倒序了,那么再把单词反转一下,单词不就正过来了。
解体思路如下:
举例,源字符串为:"the sky is blue “:
现在还需要处理的是,需要移除字符串中多余的空格,移除逻辑和 27.移除元素 的逻辑是一模一样的,只不过把移除元素改成了移除空格。
class Solution {
/**
* 思路:
* 1. 先移除多余的空格
* 2. 反转整个字符串
* 3. 反转每个单词
* hello word => drow olleh => word hello
*/
public String reverseWords(String s) {
char[] chars = s.toCharArray();
// 1. 移除多余的空格
chars = removeSpaces(chars);
// 2. 反转整个字符串
reverse(chars, 0, chars.length - 1);
// System.out.println(new String(chars));
// 3. 反转每个单词
int start = 0;
for (int i = 0; i <= chars.length; i++){
// 到达字符串尾或单词末尾 i == chars.length &&
if (i == chars.length || chars[i] == ' '){
reverse(chars, start, i - 1);
start = i + 1;
}
}
return new String(chars);
}
// 1. 使用快慢指针的方法移除字符串多余的空格
public char[] removeSpaces(char[] chars){
int slow = 0;
for(int fast = 0; fast < chars.length; fast++){
// 移除所有的空格
if(chars[fast] != ' '){
// 除第一个单词外,单词开头添加空格
if(slow != 0) chars[slow++] = ' ';
// fast 遇到空格代表遍历完一个单词
while (fast < chars.length && chars[fast] != ' '){
chars[slow++] = chars[fast++];
}
}
}
// 相当于 c++ 中的 resize()
char[] newChars = new char[slow];
System.arraycopy(chars, 0, newChars, 0, slow);
return newChars;
}
// 2. 反转字符串
public void reverse(char[] ch, int start, int end){
if (end > ch.length){
System.out.println("set a wrong end");
return;
}
while (start < end){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
}
时间复杂度:O(N)
空间复杂度:O(1)
题目:力扣 (leetcode.cn)
提升一下本题难度:不能申请额外空间,只能在本串上操作。
这题可以用 局部反转 + 整体反转 来做:
class Solution {
public String reverseLeftWords(String s, int n) {
char[] chars = s.toCharArray();
// 反转 前n子串
reverse(chars, 0, n - 1);
// 反转 n到末尾的子串
reverse(chars, n, chars.length - 1);
// 反转整个字符串
reverse(chars, 0, chars.length - 1);
return new String(chars);
}
// 反转字符串
public void reverse(char[] ch, int start, int end){
while (start < end){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
}
时间复杂度:O(N)
空间复杂度:O(1)