344.反转字符串
思路:让第一个和最后一个交换位置,第二个和倒数第二个交换位置,依次类推。
时间复杂度O(n),空间复杂度O(1)
class Solution {
public void reverseString(char[] s) {
char temp = ' ';
for (int i = 0; i < s.length / 2; i++) {
temp = s[i];
s[i] = s[s.length - 1 - i];
s[s.length - 1 - i] = temp;
}
}
}
这里交换数据的时候也可以通过位运算来交换。
class Solution {
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while (l < r) {
s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中
s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
l++;
r--;
}
}
}
541.反转字符串II
思路:反转的思路和反转数组一样,就是交换前面和后面的数据。本题重点要对反转的边界条件进行判断。
时间复杂度O(n)
class Solution {
public String reverseStr(String s, int k) {
char[] ch = s.toCharArray();
int len = ch.length;
for (int i = 0; i < len; i += (2 * k)) {
int count = 0;
if (len - i < k) { // 如果剩余字符小于k
for (int j = i; j < i + (len - i) / 2; j++) {
char temp = ch[j];
ch[j] = ch[len - 1 - count];
ch[len - 1 - count] = temp;
count++;
}
return String.valueOf(ch);
}
for (int j = i; j < i + k / 2; j++) {
char temp = ch[j];
ch[j] = ch[i + k - 1 - count];
ch[i + k - 1 - count] = temp;
count++;
}
}
return String.valueOf(ch);
}
}
记录一下随想录中的解法。在进行k的判断的时候更加简便
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){
ch[start] ^= ch[end];
ch[end] ^= ch[start];
ch[start] ^= ch[end];
start++;
end--;
}
}
return new String(ch);
}
}
剑指Offer 05.替换空格
思路:我的实现方法是开辟新的空间来进行赋值操作,这样的话实现十分简单。
时间复杂度O(n)
class Solution {
public String replaceSpace(String s) {
char[] ch = s.toCharArray();
StringBuilder sb = new StringBuilder();
for (int i = 0; i < ch.length; i++) {
if (ch[i] != ' ') {
sb.append(ch[i]);
} else {
sb.append("%20");
}
}
return sb.toString();
}
}
记录随想录上的双指针法,首先将数组扩展到将空格替换成"%20"之后的大小。然后使用双指针从后向前替换空格。(如果是从前向后的话仍然要移动数组中的元素,时间复杂度无法降低)时间复杂度O(n),空间复杂度O(1)
class Solution {
public String replaceSpace(String s) {
if(s == null || s.length() == 0) return s;
// 扩充字符串长度
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == ' ') {
sb.append(" ");
}
}
// sb长度为0说明字符串中没有空格,直接返回
if (sb.length() == 0) return s;
int left = s.length() - 1;
s += sb; // 扩充字符串长度
int right = s.length() - 1;
char[] ch = s.toCharArray();
for (; left >= 0; left--) {
if (ch[left] == ' ') {
ch[right--] = '0';
ch[right--] = '2';
ch[right--] = '%';
} else {
ch[right--] = ch[left];
}
}
return new String(ch);
}
}
151.翻转字符串里的单词
思路1:首先将多余的空格移除,然后将整个字符串反转,然后再将每个单词进行反转就可以得到目标值。
时间复杂度O(n)
class Solution {
public String reverseWords(String s) {
// 去除多余空格
StringBuilder sb = removeSpace(s);
// 反转整个字符串
reverseSting(sb, 0, sb.length() - 1);
// 反转每个单词
reverseEachWord(sb);
return sb.toString();
}
public StringBuilder removeSpace(String s) {
int start = 0, end = s.length() - 1;
while (s.charAt(start) == ' ') start++; // 删除前面多余空格
while (s.charAt(end) == ' ') end--; // 删除后面多余空格
StringBuilder sb = new StringBuilder();
while (start <= end) {
// 当s中是空格的时候,判断sb中最后一个是不是空格,如果是说明空格重复,则跳过
if (s.charAt(start) != ' ' || sb.charAt(sb.length() - 1) != ' ') {
sb.append(s.charAt(start));
}
start++;
}
return sb;
}
public void reverseSting(StringBuilder s, int start, int end) { // 反转字符串
while (start < end) {
char temp = s.charAt(start);
s.setCharAt(start, s.charAt(end));
s.setCharAt(end, temp);
start++;
end--;
}
}
public void reverseEachWord(StringBuilder s) {
int start = 0;
int end = 1;
while (end < s.length()) {
while (end < s.length() && s.charAt(end) != ' ') {
end++;
}
reverseSting(s, start, end - 1);
start = end + 1;
end = start + 1;
}
}
}
思路2:开辟一个新的字符数组,然后倒序填充单词。
时间复杂度O(n),空间复杂度O(n)
class Solution {
public String reverseWords(String s) {
char[] initialArr = s.toCharArray();
char[] newArr = new char[s.length() + 1]; // 目标数组,最后一个单词后面也添加空格,多以长度加一
int k = 0;
int i = s.length() - 1;
for (; i >=0; i--) {
while (i >= 0 && initialArr[i] == ' ') i--; // 跳过空格
int end = i;
while (i >=0 && initialArr[i] != ' ') i--; // 找到单词前一个位置
for (int j = i + 1; j <= end; j++) {
newArr[k++] = initialArr[j];
if (j == end) {
newArr[k++] = ' ';
}
}
}
return new String(newArr, 0, k - 1);
}
}
思路3:反转字符串,反转每个单词,然后通过移位删除多余空格。
时间复杂度O(n),空间复杂度O(1)
class Solution {
public String reverseWords(String s) {
char[] ch = s.toCharArray();
reverseString(ch, 0, ch.length - 1); // 反转整个字符串
int k = 0;
for (int i = 0; i < ch.length; i++) {
while (i < ch.length && ch[i] == ' ') i++;
int start = i; // 单词起始位置
while (i < ch.length && ch[i] != ' ') i++; // i指向单词结束后面一个
reverseString(ch, start, i - 1); // 反转单词
for (int j = start; j < i; j++) { // 移位删除空格
ch[k++] = ch[j];
if (j == i - 1) {
// 单词后面加空格
if (k < ch.length) { // 防止越界
ch[k++] = ' ';
}
}
}
}
// 如果字符串没有多余空格,最后一个单词就不会加空格,需要返回k
return new String(ch, 0, (k == ch.length && ch[k - 1] != ' ') ? k : k - 1);
}
public void reverseString(char[] s, int start, int end) {
while (start < end) {
s[start] ^= s[end]; // a = a^b
s[end] ^= s[start]; // b = a^b^b = a
s[start] ^= s[end]; // a = a^b^a = b
start++;
end--;
}
}
}
其实也可以使用split()按照空格分割,然后再倒序拼接,但意义不大。
剑指Offer58-II.左旋转字符串
思路:我的做法是开辟新的数组,对数组进行赋值操作,同样实现比较简单但意义不大。
时间复杂度O(n),空间复杂度O(n)
class Solution {
public String reverseLeftWords(String s, int n) {
char[] result = new char[s.length()];
int index = 0;
for (int i = n; i < s.length(); i++) {
result[index++] = s.charAt(i);
}
for (int i = 0; i < n; i++) {
result[index++] = s.charAt(i);
}
return String.valueOf(result);
}
}
随想录上的方法,先对前k个元素进行反转,然后再对后面的元素进行反转,最后对所有元素进行反转,结果就能够的到目标值。时间复杂度O(n),空间复杂度O(1)
class Solution {
public String reverseLeftWords(String s, int n) {
StringBuilder sb = new StringBuilder(s);
reverseString(sb, 0, n - 1);
reverseString(sb, n, s.length() - 1);
reverseString(sb, 0, s.length() - 1);
return sb.toString();
}
public void reverseString(StringBuilder s, int start, int end) {
while (start < end) {
char temp = s.charAt(start);
s.setCharAt(start, s.charAt(end));
s.setCharAt(end, temp);
start++;
end--;
}
}
}