力扣151(java)-颠倒字符串中的单词(中等)

题目:

给你一个字符串 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 中 至少存在一个 单词
 

进阶:如果字符串在你使用的编程语言中是一种可变数据类型,请尝试使用 O(1) 额外空间复杂度的 原地 解法。

来源:力扣(LeetCode) 和  剑指 Offer 58 - I. 翻转单词顺序

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

一、暴力求解

1.先使用trim()减去字符串两端的空格;

2.使用split()将字符串按空格分割成字符串数组;

3.使用reverse()将字符串数组进行反转;

4.最后用join()将字符串数组拼接成一个字符串。

代码:

二、双指针

1.将字符串转换成字符数组;

2.设置两个指针left和right分别指向数组的初始位置和结束位置,裁剪掉两端的空格;

3.借助index指针,从right位置开始向左遍历,直到遇到空格,然后在[index+1, right]范围内遍历字符将字符放在stringBuilder中,并添加空格;

4.然后跳过中间连续的空格,当index有字符时,代表遇到下一个字符串的结束位置,改变right的值,index继续向左遍历,直到遇到空格,后面与步骤3一致进行添加;

5.返回string类型的字符串。

 代码:

 1 class Solution {
 2     public String reverseWords(String s) {
 3         char[] s1 = s.toCharArray();
 4         StringBuilder s2 = new StringBuilder();
 5         int left = 0, right = s.length()-1;
 6         //去掉字符串左右两端的空白
 7         while(s1[left] == ' ') {
 8             left++;
 9         }
10         while(s1[right] == ' ') {
11             right--;
12         }
13         //添加单词
14         while (left <= right){
15             int index = right;
16             while(index >= left && s1[index] != ' ') {
17                 index--;
18             }
19             //当index所指为空格时,后面一位才是当前单词的初始位置
20             for(int i = index+1; i <= right; i++){
21                 s2.append(s1[i]);
22             }
23             //不是最后一个单词时都需要添加空格
24             if(index > left) s2.append(' ');
25             //跳过中间的空格,开始寻找下一个单词的位置
26             while(index >= left && s1[index] == ' '){
27                 index --;
28             }
29              right = index;
30         }
31     return s2.toString();
32     }
33 }

或者:

 1 class Solution {
 2     public String reverseWords(String s) {
 3         s = s.trim();
 4         StringBuilder sb = new StringBuilder();
 5         int fast = s.length() - 1, slow = fast;
 6         while (fast >= 0){
 7             while (fast >= 0 && s.charAt(fast) != ' ') fast--;
 8             sb.append(s.substring(fast + 1, slow + 1) + " ");
 9             while (fast >= 0 && s.charAt(fast) == ' ') fast--;
10             slow = fast;
11         }
12         return sb.toString().trim();
13 
14     }
15 }

小知识:

1.将数组转化成List集合的方法,此方法得到的list长度是不可变的

 List<String> list = Arrays.asList("aa","bb","cc");

(1)该方法适用于对象型数据的数组(String、Integer...)

对象类型(String型)的数组数组使用asList(),正常
1 String[]strings = {f"aa","bb","cc"};
2 List<String> stringList = Arrays.asList(strings);
//String类型数组使用asList(),正常:aa bb cc

(2)该方法不建议使用于基本数据类型的数组(byte,short,int,long,float,double,boolean)

 基本数据类型的数组使用asList(),出错
1 int[] ints = new int[]{1,2,3};
2 List intList = Arrays.asList(ints);
//基本数据类型的数组使用asList(),出错(输出的是一个引用,把ints当成一个元素了):[I@1540e19d这样遍历才能正确输出: 1 2 3

(3)该方法将数组与List列表链接起来:当更新其一个时,另一个自动更新

(4)不支持add()、remove()、clear()等方法
2.split("\\s+")和split("+"):

\s 表示:匹配任何空白字符,包括空格、制表符、换页符等等。等价于[ \f\n\r\t\v]
+ 表示:匹配前面的子表达式一次或多次。
\s+ 表示:以空格、换行符、回车为分割线,相邻的多个空格、换行符、回车仍然视为只有一个,分隔后返回字符数组

 3.Collections类是集合类的一个工具类其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作,常用方法:

public class test{
     public static void main(String[] args){
               List  list = new ArrayList();
               list.add("b");
               list.add("s");
               list.add("t");
               list.add("a");
               //1.对集合进行排序--[a,b,s,t]
               Collections.sort(list);
               System.out.println(list);
               //2.对集合进行随机排序--[s,a,t,b]
               Collections.shuffle(list);
               System.out.println(list);
               //3.查找指定集合中的元素,返回所查找元素的索引--1
               int n = Collections.binarySearch(list, "s");
               System.out.println(n);
               //4.反转集合中的元素--[t,s,b,a]
               Collections.reverse(list);
               System.out.println(list);
               //5.替换某元素,若要替换的值存在返回true,反之返回false --true,[b,s,t,f,p]
               System.out.println(Collections.replaceAll(list, "a","f p"));
               //6.集合中的元素向后移m个位置,在后面被遮盖的元素循环到前面来--[a,b,s,t]
               Collections.rotate(list, 1);
               System.out.println(list);
               //7.将集合n中的元素全部赋值到list中,并且覆盖相应索引的元素--[one, two, three, a]
               List n = Arrays.asList("one two three".split(" "));
               Collections.copy(list, n)    
               System.out.println(list);   
               //8.交换集合中指定元素索引的位置--[b, s, a, t]
               Collections.swap(list, 2, 3);
               System.out.println(list); 

        } 
}

4.Java String join()方法返回一个新字符串,该字符串具有给定的元素和指定的分隔符。

String.join(CharSequence delimiter,CharSequence... elements)将elements用指定的字符串delimeter连接起来
delimiter:与元素连接的连接符
elements:连接的元素
...: 表示可以有一个或多个CharSequence(字符序列)。
注意: join()是静态方法。您无需创建字符串对象即可调用此方法。使用类名称String调用该方法。
例如:
String message = String.join("-", "java", "is", "cool"); //返回的是“java-is-cool”

5.char[] s1 = s.toCharArray():将字符串s转换成一个char类型的数组。

6.在使用无参构造来构造StringBuilder对象:

StringBuilder s2 = new StringBuilder();

Java String、StringBuffer 和 StringBuilder 的区别:

  • string字符串常量,字符串长度不可变,每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响;
  • stringBuffer:字符串变量(Synchronized,即线程安全)。如果要频繁对字符串内容进行修改,出于效率考虑最好使用 StringBuffer,如果想转成 String 类型,可以调用 StringBuffer 的 toString() 方法;
  • stringBuilder:字符串变量(非线程安全)。在内部,StringBuilder 对象被当作是一个包含字符序列的变长数组,在执行速度方面的比较:StringBuilder > StringBuffer.

使用原则:

  • 如果要操作少量的数据用 :String
  • 单线程操作字符串缓冲区 下操作大量数据 : StringBuilder
  • 多线程操作字符串缓冲区 下操作大量数据 : StringBuffer

7.toString()方法将对象转换为字符串。

posted on 2022-05-09 10:06  我不想一直当菜鸟  阅读(145)  评论(0编辑  收藏  举报