Leetcode--Java--151. 翻转字符串里的单词

题目描述

给你一个字符串 s ,逐个翻转字符串中的所有 单词 。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
请你返回一个翻转 s 中单词顺序并用单个空格相连的字符串。
说明:
输入字符串 s 可以在前面、后面或者单词间包含多余的空格。
翻转后单词间应当仅用一个空格分隔。
翻转后的字符串中不应包含额外的空格。

样例描述

示例 1:

输入:s = "the sky is blue"
输出:"blue is sky the"
示例 2:

输入:s = "  hello world  "
输出:"world hello"
解释:输入字符串可以在前面或者后面包含多余的空格,但是翻转后的字符不能包括。

思路

字符串的常见处理
方法一: 两次翻转

  1. 难点:以单词为最小单位进行翻转。将这个难点分解为两步如下,
    第一步,将整个字符串以字符为单位翻转。
    第二步,将每个单词进行翻转。
    上面这两步可以互换,是等价的(画图可以看出)
    在这里插入图片描述
  2. 删空格,从前往后枚举有效空格,将有效的字符放在数组最前面,每次移动都是搜寻一个单词,移动后记得补上1个空格
    在这里插入图片描述
    方法二:双指针 + 一次遍历实现翻转
    本方法思路具有跳跃性,不需要真正实现“翻转”。具体如下:
  3. 由于是要反转字符里的单词,可以双指针(指向左右边界)从后往前遍历,不断寻找单词,然后加入到结果集同时加一个分隔空格。循环直到找完所有的或者边界越界。 最后再删除最后一个单词后面的多余空格。 (有点取巧的感觉。。。不过确实牛逼)
  4. 关键:整个从后往前处理,直接截取单词

上述两种方法都涉及到StringBuffer很多做字符串处理的常用函数

代码

方法一:

class Solution {
    
    
    public String reverseWords(String s) {
    
    
       StringBuffer sb = new StringBuffer(s);
       int n = s.length();
       //用来索引有效字符的下标
       int k = 0;
       for (int i = 0; i < n; i ++ ) {
    
    
           //过滤无效空格
           if (sb.charAt(i) == ' ') continue;
           //先第一步,将每个单词翻转
           int j = i, t = k; //t记录单词的第一个字符
           //j来确定单词的下标范围,k用来查找单词末尾的字符
           while (j < n && sb.charAt(j) != ' ') sb.setCharAt(k ++, sb.charAt(j ++ ));
           //翻转单词
           reverse(sb, t, k - 1);
           //补充一个空格分隔,注意是否越界 超过就不能补
           if (k < n) sb.setCharAt(k ++, ' ');
           i = j;
       }
       //如果k前面还有空格,即多加了最后一个单词后的空格,要减一,与后面的空格一起删除
       if (sb.charAt(k - 1) == ' ') k --;
       sb.delete(k, n);
       //第二步,翻转整个字符串 前面删掉了k及后面部分,所以剩余长度到k - 1
       reverse(sb, 0, k - 1);
       return sb.toString();
    }
    public void reverse(StringBuffer sb, int l, int r) {
    
    
        while (l < r) {
    
    
            char c = sb.charAt(l);
            sb.setCharAt(l, sb.charAt(r));
            sb.setCharAt(r, c);
            l ++;
            r --;
        }
    }
}

方法二:

class Solution {
    
    
    public String reverseWords(String s) {
    
    
       int n = s.length();
       int left = n - 1, right = n - 1;
       StringBuffer res = new StringBuffer();
       //左边界没越界时
       while (left >= 0) {
    
    
           //从后往前先找到第一个字符,也就是末尾单词的右边界
           while (left >= 0 && s.charAt(left) == ' ') left --;
           //如果已经越界,说明不存在了,直接退
           if (left < 0) break;
           right = left;
           //接下来寻找末尾单词的左边界,继续往后找到第一个空格
           while (left >= 0 && s.charAt(left) != ' ') left --;
           //截取单词放进结果集 [left + 1, right] 注意substring不含右边所以加一
           res.append(new StringBuffer(s.substring(left + 1, right + 1)));
           //追加分隔空格
           res.append(' ');
       }
       //清除最后一个单词后面的空格
       return res.deleteCharAt(res.length() - 1).toString();
    }
}

Guess you like

Origin blog.csdn.net/Sherlock_Obama/article/details/121170056