方法1:双指针遍历倒插(重点掌握的方法)
首先我们把题目给的String转换为char[],还要有一个StringBuilder接收答案。通过从指针从头尾开始遍历,如果指的值为空格,均往中间移动,直到不为空格,这样就剪掉了首尾空格。因为要单词反转,所以从后面的right开始寻找单词,从right的位置,用一个index指针往左移动,找到为空格的位置停止,然后将index+1倒right的位置的单词遍历放入到StringBuilder。接着index继续移动找到不为空格的位置,然后把right更新过来,后面接着同样的操作知道完成数组的遍历得到答案。其实全程除了除去首尾空白,left都没动过,right也是靠index来更新,主要是index的移动。
由于思路光用语言难以表达,为大家找到一篇优质图解,建议认真观看一下——双指针图解
时间复杂度O(n):n为s的长度,只遍历了一次
空间复杂度O(n):主要用来存储字符串,因语言而定,字符串可变的语言空间复杂度可为O(1)
class Solution { public String reverseWords(String s) { //转换为char数组 char[] arr = s.toCharArray(); int left = 0; int right = arr.length-1; //用来接收答案 StringBuilder sb = new StringBuilder(); //去掉空格 while(arr[left]==' ') left++; while(arr[right] == ' ') right--; //注意循环结束条件 while(left <= right){ //index从right开始出发 int index = right; //找到为空的地方停下来,这里要注意也得大于等于left,不然在走到最左边可能会数组越界 while(index >= left && arr[index] != ' ' ) index--; //注意此时index是指向空格的,从inde+1到right一个个字符加入到StringBuilder中 for(int i = index+1 ; i <= right ; i++ ) sb.append( arr[i] ); //因为中间的单词之间需要加空格,所以index>left时,说明还在中间,我们补一个空格 if(index > left) sb.append(' '); //然后我们继续移动index找到下一个单词的,这时也要保证index>=left,原理同上 while( index >= left && arr[index]==' ' ) index--; //然后更新right到index right = index; } return sb.toString(); } }
方法2:API大法(虽然复杂度差不多,但其实效率比双指针低)
时间复杂度:O(n),其中 nn 为输入字符串的长度。
空间复杂度:O(n)O(n),用来存储字符串分割之后的结果
上面我们讲了这道题的考点解析,如果我们都能够用API来完成这些需求,那么代码就会很简单,前提是大家要会使用和了解这些API。
官方题解的API:
class Solution { public String reverseWords(String s) { // 除去开头和末尾的空白字符 s = s.trim(); // 正则匹配连续的空白字符作为分隔符分割 List<String> wordList = Arrays.asList(s.split("\\s+")); //Collections带的reverse方法可以之间反转,但需要传入一个List Collections.reverse(wordList); //String.join方法很冷门,它可以在第二个参数的两两元素之间插入第一个参数 return String.join(" ", wordList); } }
我写的API法:
class Solution { public String reverseWords(String s) { //去掉首尾空格的API,需要会用 String c=s.trim(); //以连续的空格为切割符,这里涉及到正则表达式 //ps:split的使用很广泛,请一定要学会 String[] arr=c.split("\\s+"); StringBuilder a=new StringBuilder(); //从 for(int i=arr.length-1;i>=0;i--){ //从尾向头一个个单词插入 //每次插入后补一个空格 a.append(arr[i]+" "); } //最后一个单词后面不用空格,删掉最后一个 a.deleteCharAt(a.length()-1); return a.toString(); } }
🍑5.左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
题目链接:左旋转字符串 https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
题目分析:题目的要求很简单,无非就是将前n个字符移到后面即可,我们可以用StringBuilder或者StringBuffer先接收后面的字符,再接收前n个字符。
方法1:StringBuffer接收
时间复杂度O(n):n为s的长度,遍历的耗时
空间复杂度O(n):主要是StringBuffer的消耗
PS:若面试要求只能用String,这里也可用String,只不过Python和Java中的String不可变,每次都要新建一个字符串且拼接的效率低,每次都要申请内存,当数据量大时效率低,且申请内存高。
class Solution { public String reverseLeftWords(String s, int n) { StringBuffer a=new StringBuffer(); for(int i=n;i<s.length();i++){ a.append(s.charAt(i)); } for(int i=0;i<n;i++){ a.append(s.charAt(i)); } return a.toString(); } }