LeetCode面试150——151反转字符串中的单词

题目难度:中等

默认优化目标:最小化平均时间复杂度。

Python默认为Python3。

目录

1 题目描述

2 题目解析

3 算法原理及代码实现

3.1 模拟

3.2 双端队列

参考文献


1 题目描述

给你一个字符串 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) 额外空间复杂度的 原地 解法。

2 题目解析

输入是一个字符串s,输出是反转后的字符串。它的翻转仅是对单词出现顺序而言,单词本身不反转。同时反转后不能出现前导空格和尾随空格。题目中提到s至少存在一个 单词,我们不用判断s为空的情况。

3 算法原理及代码实现

3.1 模拟

我们可以把翻转字符串中的单词拆分成3个模块:① 分割字符串中的单词;② 将单词顺序反转;③ 将单词连接起来。

平均时间复杂度O(n),平均空间复杂度O(n)。

C++代码实现

#include <sstream>
#include <vector>
#include <algorithm>
​
class Solution {
public:
    string reverseWords(string s) {
        istringstream iss(s);
        vector<string> words;
        string word;
        
        //逐个读取单词
        while (iss >> word) {
            words.push_back(word);
        }
        
        //反转
        reverse(words.begin(), words.end());
        
        //拼接
        ostringstream oss;
        for (size_t i = 0; i < words.size(); ++i) {
            if (i != 0) {
                oss << " ";
            }
            oss << words[i];
        }
        
        return oss.str();
    }
};

Python代码实现

class Solution:
    def reverseWords(self, s: str) -> str:
        return " ".join(reversed(s.split()))

Java代码实现

class Solution {
    public String reverseWords(String s) {
        s=s.trim();//去除首尾空白字符
        String[] words = s.split("\\s+");//按空白字符分割
        Collections.reverse(Arrays.asList(words));
        return String.join(" ", words);
    }
}

对C++代码进行改动,我们可以实现O(1)的平均空间复杂度

C++实现O(1)空间复杂度

class Solution {
public:
    string reverseWords(string s) {
        // 反转整个字符串
        reverse(s.begin(), s.end());
​
        int n = s.size();
        int idx = 0;
        for (int start = 0; start < n; start++) {
            if (s[start] != ' ') {
                // 填一个空白字符然后将idx移动到下一个单词的开头位置
                if (idx != 0) s[idx++] = ' ';
​
                // 循环遍历至单词的末尾
                int end = start;
                while (end < n && s[end] != ' ') s[idx++] = s[end++];
​
                // 反转整个单词
                reverse(s.begin() + idx - (end - start), s.begin() + idx);
​
                // 更新start,去找下一个单词
                start = end;
            }
        }
        s.erase(s.begin() + idx, s.end());
        return s;
    }
};

3.2 双端队列

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

平均时间复杂度为O(n),平均空间复杂度为O(1)。

C++代码实现

#include <deque>
#include <string>
#include <algorithm>
​
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));
        
        // 使用 s 作为返回字符串
        s.clear();
        while (!d.empty()) {
            s += d.front();
            d.pop_front();
            if (!d.empty()) s += ' ';
        }
        return s;
    }
};
​

Python代码实现

from collections import deque
​
class Solution:
    def reverseWords(self, s: str) -> str:
        left, right = 0, len(s) - 1
        # 去掉字符串开头的空白字符
        while left <= right and s[left] == ' ':
            left += 1
​
        # 去掉字符串末尾的空白字符
        while left <= right and s[right] == ' ':
            right -= 1
​
        d = deque()
        word = []
​
        while left <= right:
            char = s[left]
            if word and char == ' ':
                # 将单词 push 到队列的头部
                d.appendleft(''.join(word))
                word = []
            elif char != ' ':
                word.append(char)
            left += 1
        d.appendleft(''.join(word))
        
        # 使用 s 作为返回字符串
        return ' '.join(d)
 

Java代码实现

import java.util.*;
​
class Solution {
    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<>();
        StringBuilder word = new StringBuilder();
​
        while (left <= right) {
            char c = s.charAt(left);
            if (word.length() > 0 && c == ' ') {
                // 将单词 push 到队列的头部
                d.addFirst(word.toString());
                word.setLength(0);
            } else if (c != ' ') {
                word.append(c);
            }
            left++;
        }
        d.addFirst(word.toString());
        
        // 使用 StringBuilder 作为返回字符串
        StringBuilder result = new StringBuilder();
        while (!d.isEmpty()) {
            result.append(d.pollFirst());
            if (!d.isEmpty()) result.append(' ');
        }
        return result.toString();
    }
​
    public static void main(String[] args) {
        Solution solution = new Solution();
        String s = "the sky is blue";
        System.out.println(solution.reverseWords(s));
    }
}
 

参考文献

力扣面试经典150题

力扣官方题解

  • 14
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值