• 151. 翻转字符串里的单词


    题目:https://leetcode-cn.com/problems/reverse-words-in-a-string/

    自己的思路:使用两个指针,i 指针负责从后向前遍历整个字符串,j 指针找到单词的末尾字符,单词开头的特点是:空格+字符(字符串的开头添加一个空格);单词末尾的特点:字符+空格/字符;

    JAVA:
    public static String reverseWords(String s) { StringBuilder str = new StringBuilder(); s = " "+s;//字符串的开头添加一个空格 for (int i = s.length() - 1, j = s.length() - 1; i >= 1; i--){ if (s.charAt(i - 1) != ' ' && s.charAt(i) == ' '){//如果 i 所指位置为空,前一位不为空,则说明前一位为单词的结尾,将 j 指向此处; j = i-1; } if (s.charAt(i - 1) == ' ' && s.charAt(i) != ' ') {//如果 i 所指位置不为空,前一位为空,则说明找到了该单词的开头,截取头和尾之间的字符串即为一个单词,并在单词后添加一个空格。 String temp = s.substring(i, j+1); str.append(temp+" "); } } str.deleteCharAt(str.length()-1);//去除末尾多余的一个空格 return str.toString(); }

    知识点:

    delete方法与deleteCharAt两个方法都是用来删除StringBuffer字符串指定索引字符的方法,

    java.lang.StringBuffer.delete(int a,int b)有两个参数,使用时删除索引从a开始(包含a)到b(不包含b)的所有字符;

    java.lang.StringBuffer.deleteCharAt(int a)只有一个参数,使用时删除索引为a的字符;

    效果:

    官方:https://leetcode-cn.com/problems/reverse-words-in-a-string/solution/fan-zhuan-zi-fu-chuan-li-de-dan-ci-by-leetcode-sol/

    方法一:使用语言特性

    很多语言对字符串提供了 split(拆分),reverse(翻转)和 join(连接)等方法,因此我们可以简单的调用内置的 API 完成操作:

    • 使用 split 将字符串按空格分割成字符串数组;
    • 使用 reverse 将字符串数组进行反转;
    • 使用 join 方法将字符串数组拼成一个字符串。

    JAVA:
    public
    String reverseWords(String s) { // 除去开头和末尾的空白字符 s = s.trim(); // 正则匹配连续的空白字符作为分隔符分割 List<String> wordList = Arrays.asList(s.split("\s+")); Collections.reverse(wordList); return String.join(" ", wordList); }

     方法二:自行编写对应的函数

    我们也可以不使用语言中的 API,而是自己编写对应的函数。在不同语言中,这些函数实现是不一样的,主要的差别是有些语言的字符串不可变(如 Java 和 Python),有些语言的字符串可变(如 C++)。

    对于字符串不可变的语言,首先得把字符串转化成其他可变的数据结构,同时还需要在转化的过程中去除空格。

    对于字符串可变的语言,就不需要再额外开辟空间了,直接在字符串上原地实现。在这种情况下,反转字符和去除空格可以一起完成。

     

    JAVA:
    public String reverseWords(String s) {
            StringBuilder sb = trimSpaces(s);
    
            // 翻转字符串
            reverse(sb, 0, sb.length() - 1);
    
            // 翻转每个单词
            reverseEachWord(sb);
    
            return sb.toString();
        }
    
        public StringBuilder trimSpaces(String s) {
            int left = 0, right = s.length() - 1;
            // 去掉字符串开头的空白字符
            while (left <= right && s.charAt(left) == ' ') {
                ++left;
            }
    
            // 去掉字符串末尾的空白字符
            while (left <= right && s.charAt(right) == ' ') {
                --right;
            }
    
            // 将字符串间多余的空白字符去除
            StringBuilder sb = new StringBuilder();
            while (left <= right) {
                char c = s.charAt(left);
    
                if (c != ' ') {
                    sb.append(c);
                } else if (sb.charAt(sb.length() - 1) != ' ') {
                    sb.append(c);
                }
    
                ++left;
            }
            return sb;
        }
    
        public void reverse(StringBuilder sb, int left, int right) {
            while (left < right) {
                char tmp = sb.charAt(left);
           //public void setCharAt(int index, char ch) 很简单,把第index位的字符替换成ch  sb.setCharAt(left
    ++, sb.charAt(right)); sb.setCharAt(right--, tmp); } } public void reverseEachWord(StringBuilder sb) { int n = sb.length(); int start = 0, end = 0; while (start < n) { // 循环至单词的末尾 while (end < n && sb.charAt(end) != ' ') { ++end; } // 翻转单词 reverse(sb, start, end - 1); // 更新start,去找下一个单词 start = end + 1; ++end; } }

    C++: 别人写的

    https://programmercarl.com/0151.%E7%BF%BB%E8%BD%AC%E5%AD%97%E7%AC%A6%E4%B8%B2%E9%87%8C%E7%9A%84%E5%8D%95%E8%AF%8D.html#%E5%85%B6%E4%BB%96%E8%AF%AD%E8%A8%80%E7%89%88%E6%9C%AC

    class Solution {
    public:
        // 反转字符串s中左闭又闭的区间[start, end]
        void reverse(string& s, int start, int end) {
            for (int i = start, j = end; i < j; i++, j--) {
                swap(s[i], s[j]);
            }
        }
    
        // 移除冗余空格:使用双指针(快慢指针法)O(n)的算法
        void removeExtraSpaces(string& s) {
            int slowIndex = 0, fastIndex = 0; // 定义快指针,慢指针
            // 去掉字符串前面的空格
            while (s.size() > 0 && fastIndex < s.size() && s[fastIndex] == ' ') {
                fastIndex++;
            }
            for (; fastIndex < s.size(); fastIndex++) {
                // 去掉字符串中间部分的冗余空格
                if (fastIndex - 1 > 0
                        && s[fastIndex - 1] == s[fastIndex]
                        && s[fastIndex] == ' ') {
                    continue;
                } else {
                    s[slowIndex++] = s[fastIndex];
                }
            }
            if (slowIndex - 1 > 0 && s[slowIndex - 1] == ' ') { // 去掉字符串末尾的空格
                s.resize(slowIndex - 1);
            } else {
                s.resize(slowIndex); // 重新设置字符串大小
            }
        }
    
        string reverseWords(string s) {
            removeExtraSpaces(s); // 去掉冗余空格
            reverse(s, 0, s.size() - 1); // 将字符串全部反转
            int start = 0; // 反转的单词在字符串里起始位置
            int end = 0; // 反转的单词在字符串里终止位置
            bool entry = false; // 标记枚举字符串的过程中是否已经进入了单词区间
            for (int i = 0; i < s.size(); i++) { // 开始反转单词
                if (!entry) {
                    start = i; // 确定单词起始位置
                    entry = true; // 进入单词区间
                }
                // 单词后面有空格的情况,空格就是分词符
                if (entry && s[i] == ' ' && s[i - 1] != ' ') {
                    end = i - 1; // 确定单词终止位置
                    entry = false; // 结束单词区间
                    reverse(s, start, end);
                }
                // 最后一个结尾单词之后没有空格的情况
                if (entry && (i == (s.size() - 1)) && s[i] != ' ' ) {
                    end = i;// 确定单词终止位置
                    entry = false; // 结束单词区间
                    reverse(s, start, end);
                }
            }
            return s;
        }
        
        // 当然这里的主函数reverseWords写的有一些冗余的,可以精简一些,精简之后的主函数为:
        /* 主函数简单写法
        string reverseWords(string s) {
            removeExtraSpaces(s);
            reverse(s, 0, s.size() - 1);
            for(int i = 0; i < s.size(); i++) {
                int j = i;
                // 查找单词间的空格,翻转单词
                while(j < s.size() && s[j] != ' ') j++;
                reverse(s, i, j - 1);
                i = j;
            }
            return s;
        }
        */
    };

    方法三:双端队列
    由于双端队列支持从队列头部插入的方法,因此我们可以沿着字符串一个一个单词处理,然后将单词压入队列的头部,再将队列转成字符串即可。

     JAVA双端队列:https://www.cnblogs.com/walxt/p/12442506.html

    JAVA:
    public String reverseWords(String s) {
            int left = 0, right = s.length() - 1;
            // 去掉字符串开头的空白字符
            while (left <= right && s.charAt(left) == ' ') {
                ++left;
            }
    
            // 去掉字符串末尾的空白字符
            while (left <= right && s.charAt(right) == ' ') {
                --right;
            }
    
            Deque<String> d = new ArrayDeque<String>();
            StringBuilder word = new StringBuilder();
            
            while (left <= right) {
                char c = s.charAt(left);
                if ((word.length() != 0) && (c == ' ')) {
                    // 将单词 push 到队列的头部
                    d.offerFirst(word.toString());
                    word.setLength(0);
                } else if (c != ' ') {
                    word.append(c);
                }
                ++left;
            }
            d.offerFirst(word.toString());
    
            return String.join(" ", d);
        }
    C++:
    class Solution {
    public:
        string reverseWords(string s) {
            int left = 0, right = s.size() - 1;
            // 去掉字符串开头的空白字符
            while (left <= right && s[left] == ' ') ++left;
    
            // 去掉字符串末尾的空白字符
            while (left <= right && s[right] == ' ') --right;
    
            deque<string> d;
            string word;
    
            while (left <= right) {
                char c = s[left];
                if (word.size() && c == ' ') {
                    // 将单词 push 到队列的头部
                    d.push_front(move(word));
                    word = "";
                }
                else if (c != ' ') {
                    word += c;
                }
                ++left;
            }
            d.push_front(move(word));
            
            string ans;
            while (!d.empty()) {
                ans += d.front();
                d.pop_front();
                if (!d.empty()) ans += ' ';
            }
            return ans;
        }
    };
     
  • 相关阅读:
    每日英语:Italian town fighting for its life over polluting Ilva steelworks
    SpringBoot + Kafka + ELK 完成海量日志收集(超详细)
    如何使用 Java 生成二维码?
    xyntservice
    windows service 与GUI窗口的实现
    一个可以查看HTML网页上密码框的程序(附源码)
    vss6 forgot admin password
    vs2005's addin folder
    javascript tips
    html中使用imagemap
  • 原文地址:https://www.cnblogs.com/wltree/p/15370839.html
Copyright © 2020-2023  润新知