力扣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
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)