《剑指Offer》-58-翻转单词顺序/力扣-151-反转字符串中的单词

发布时间 2023-08-13 02:30:41作者: YaosGHC

可以使用栈,将每个单词(字符串)压栈,然后弹栈就 OK 了

好吧,实际写下来考虑到可能存在的多余空格问题,代码看起来并不简介,而且写之前就很明显直到需要最差额外 n 的空间,时间复杂度最差 2n,所以都不算好

思路是压栈的时候只压单词本身,弹栈的时候再去拼空格

	string reverseWords(string s) {
		s += ' ';// 加一个空格避免需要额外清空temp
		stack<string> stk;
		string temp;
		for (char ch : s) {
			if (ch != ' ') temp += ch;
			else if (!temp.empty()) {
				stk.push(temp);
				temp.clear();
			}
		}

		int numOfWord = stk.size();
		if (numOfWord == 0) return "";
		for (int i = 0; i < numOfWord - 1; i++) {
			temp = temp + stk.top() + ' ';
			stk.pop();
		}

		return temp+stk.top();
	}

需要额外注意栈空的情况,不然会指针越界

然后就是这种做法真的 时间/空间复杂度 都很差

	string reverseWords(string s) {
		string temp,res;

		int notZero = 0;
		while (s[notZero] == ' ') notZero++;

		// 从后往前扫描,最后一位不能是0
		for (int i = s.size() - 1; i >= notZero; i--) {
			if (s[i] != ' ') temp.insert(temp.begin(),s[i]);
			else if (!temp.empty()) {
				res = res + temp + " ";
				temp.clear();
			}
		}
		return res+temp;
	}

换一个思路,效率仍然很差,我觉得问题出在insert()之后每次的移动上面

最终思路我想应该是将每一个单词翻转,然后将整个字符串翻转

	string reverseWords(string s) {
		s += ' ';
		int start = 0, end;
		while (s[start] == ' ') s.erase(s.begin());

		for (; start < s.size(); start++) {
			if (s[start] != ' ') {
				for (end = start + 1; end < s.size(); end++) {
					if (s[end] == ' ') {
						reverse(s.begin() + start, s.begin() + end);
						start = end;
						break;
					}
				}
			}
		}

		reverse(s.begin(), s.end());// 至此完成翻转,接下来提取单词
		start = 0;
		while (s[start] == ' ') s.erase(s.begin());

		// 删除中间多余空格
		for (start = 0; start < s.size(); start++) {
			if (s[start] == ' ' && (start + 1) < s.size()) {
				while (s[start + 1] == ' ')s.erase(s.begin() + start + 1);
			}
		}

		return s;
	}

AC 代码,不能说是最完美的,但是应该足够完美了,有几个巧思

  1. s 一上来就追加一个' ',这样可以保证挨个单词翻转的时候不用追加最后一步操作
  2. 翻转前删除头部所有空格,翻转后再删除一遍头部所有空格(其实就是没翻转前的尾空格),这样也删除了第一步自己追加的空格,这样做很省事也很见简单

另外就是原地操作数组需要格外注意指针越界的情况

string reverseWords(string s) {
    int len = s.size();
    int start = 0, end = 0;
    bool wordStarted = false;
    
    for (int i = 0; i < len; i++) {
        if (s[i] != ' ') {
            if (!wordStarted) {
                if (start != 0) s[end++] = ' '; // 添加空格分隔符
                start = end; // 记录单词起始位置
                wordStarted = true;
            }
            s[end++] = s[i]; // 复制字符
        } else {
            wordStarted = false;
        }
    }
    
    s.resize(end); // 调整字符串长度
    
    reverse(s.begin(), s.end()); // 整体翻转字符串
    
    start = 0;
    len = s.size();
    for (int i = 0; i < len; i++) {
        if (s[i] != ' ' || (i > 0 && s[i - 1] != ' ')) {
            s[start++] = s[i]; // 去除多余空格
        }
    }
    
    s.resize(start);
    return s;
}

GPT 给出的时间复杂度可以优化至O(N)的代码(未验证)