344.反转字符串
双指针:
class Solution {
public void reverseString(char[] s) {
int left = 0;
int right = s.length-1;
while(left < right){
char temp = s[left];
s[left] = s[right];
s[right] = temp;
left++;
right--;
}
}
}
递归实现:
public void reverseString(char[] s) {
recursion(s,0,s.length-1);
}
public void recursion(char[] s,int left,int right){
if(left >= right){
return;
}
char temp = s[left];
s[left] = s[right];
s[right] = temp;
recursion(s,left+1,right-1);
//交换元素和继续递归的代码可以互换
}
补充:
位运算进行交换:
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 完成交换
541.反转字符串II
暴力解法:
class Solution {
public String reverseStr(String s, int k) {
int left = 0;
int right = 0;//记录2k处
int mid = 0;//记录k处
int count = 1;
char[] ch = s.toCharArray();
//注意控制边界
while(left<s.length()){
System.out.println("count=="+count);
right = left + 2*k*process(count)-1;
mid = left + k*process(count)-1;
System.out.println("right=="+right);
System.out.println("mid=="+mid);
if(mid >= s.length()){//说明前面不足k个元素
System.out.println("mid下标越界");
reverse(ch,left,s.length()-1);
break;
}
if(right >= s.length()){//足k个元素,但是不足2k个元素
System.out.println("right下标越界");
reverse(ch,left,mid);
break;
}
reverse(ch,left,mid);
//变化left
left = right+1;
count++;
}
return new String(ch);
}
//根据轮次辅助计算left mid right
public int process(int n){
int result = 0;
if(result == 0){
result = 1;
n--;
}else{
while(n>0){
result = result + result*2;
n--;
}
}
return result;
}
//实现反转
public void reverse(char[] s,int start,int end){
System.out.println("start=="+start);
System.out.println("end=="+end);
while(start < end){
char temp = s[start];
s[start] = s[end];
s[end] = temp;
start++;
end--;
}
}
}
找规律,用循环。
class Solution {
public String reverseStr(String s, int k) {
char[] cs = s.toCharArray();
int n = s.length();//字符串的长度
//循环
for (int l = 0; l < n; l = l + 2 * k) {//l = l + 2 * k下一轮开始处,即left
int r = l + k - 1;//注意要-1
//我的三种情况其实都可以统一成一行代码
reverse(cs, l, Math.min(r, n - 1));
}
return String.valueOf(cs);
}
void reverse(char[] cs, int l, int r) {
while (l < r) {
char c = cs[l];
cs[l] = cs[r];
cs[r] = c;
l++; r--;
}
}
}
替换空格
剑指offer 05
对于线性数据结构,填充或者删除,后序处理会高效的多。
双指针法:
i指向新长度的末尾,j指向旧长度的末尾。
class Solution {
public String replaceSpace(String s) {
if(s == null || s.length()==0){
return s;
}
int count = 0;
for(int i=0;i<s.length();i++){
if(s.charAt(i) == ' '){
count++;
}
}
char[] ch = new char[s.length()+2*count];
int newArray = ch.length-1;
for(int i=s.length()-1;i>=0;i--){//遍历一遍
if(s.charAt(i) == ' '){
ch[newArray] = '0';
ch[--newArray] = '2';
ch[--newArray] = '%';
}else{
ch[newArray] = s.charAt(i);
}
newArray--;
}
return new String(ch);
}
}
利用StringBuilder:
public static String replaceSpace(String s) {
if (s == null) {
return null;
}
//选用 StringBuilder 单线程使用,比较快,选不选都行
StringBuilder sb = new StringBuilder();
//使用 sb 逐个复制 s ,碰到空格则替换,否则直接复制
for (int i = 0; i < s.length(); i++) {
//s.charAt(i) 为 char 类型,为了比较需要将其转为和 " " 相同的字符串类型
//if (" ".equals(String.valueOf(s.charAt(i)))){}
if (s.charAt(i) == ' ') {
sb.append("%20");
} else {
sb.append(s.charAt(i));
}
}
return sb.toString();
}
}
151.翻转字符串里的单词
借助ArrayList集合,将s中的每一个单词按序放入list集合中。再倒序遍历list集合,得到最终的结果。
class Solution {
public String reverseWords(String s) {
int left = 0;
while(s.charAt(left) == ' '){
left++;
}
List<String> list = new ArrayList<>();
//此时left指向不为' '的最左下标
while(left < s.length()){
StringBuilder sb = new StringBuilder();
while(left < s.length() && s.charAt(left) != ' '){
sb.append(s.charAt(left));
left++;
}
list.add(new String(sb));
while(left < s.length() && s.charAt(left) == ' '){
left++;
}
}
StringBuilder result = new StringBuilder();
for(int i=list.size()-1;i>=0;i--){
result.append(list.get(i));
if(i != 0){
result.append(" ");
}
}
return new String(result);
}
}
不要使用辅助空间,空间复杂度要求为O(1)。
先整体反转,再局部反转。
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();
}
//利用StringBuilder进行reverse
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--;
}
}
public void reverseEachWord(StringBuilder sb){
int start = 0;
int end = 0;
while(start < sb.length()){//定start
//注意
while(end < sb.length() && sb.charAt(end) != ' '){
end++;
}
//此时end是指向空格
//截取
reverseString(sb,start,end-1);
start = end+1;
end = start;
}
}
public StringBuilder removeSpace(String s){
StringBuilder sb = new StringBuilder();
int start = 0;
int end = s.length()-1;
while(s.charAt(start) == ' '){
start++;
}
while(s.charAt(end) == ' '){
end--;
}
while(start <= end){
char c = s.charAt(start);
//※
if (c != ' ' || sb.charAt(sb.length() - 1) != ' ') {//保证有空格的话能加一个空格进来
sb.append(c);
}
start++;
}
return sb;
}
左旋转字符串
剑指offer 58
最直接的想法:
class Solution {
public String reverseLeftWords(String s, int n) {
if(n >= s.length()){
return s;
}
StringBuilder sb = new StringBuilder();
for(int i=n;i < s.length();i++){
sb.append(s.charAt(i));
}
for(int i=0;i<n;i++){
sb.append(s.charAt(i));
}
return new String(sb);
}
}
不能申请额外空间,只能在本串上操作。
先局部,再整体。
class Solution {
public String reverseLeftWords(String s, int n) {
int len=s.length();
StringBuilder sb=new StringBuilder(s);
reverseString(sb,0,n-1);//反转前n
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--;
}
}
}