Swift 数据结构与算法(42 ) + Leetcode 掘金151. 反转字符串中的单词

44 阅读3分钟

Swift 数据结构与算法( ) + Leetcode 掘金 #日新计划更文活动

题目

151. 反转字符串中的单词

labuladong 题解

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

解题思路🙋🏻‍ ♀️

边界思考🤔

代码

**class** Solution {

    **func** reverseWords(_ s: String) -> String {

         

        **var** chars = Array(s)

        

        **var** left = 0

        **var** right = chars.count - 1

        

        reverseWord(chars: &chars, start: 0, end: right)

        

        //原地反转每个单词

        **var** start = 0

        **for** end **in** 0...chars.count {

            **if** end == chars.count || chars[end] == " " {

                reverseWord(chars: &chars, start: start, end: end - 1)

                start = end + 1

            }

        }

        

        //2.0

        

        **var** index = 0

        **var** isFirstSpace = **true**

        **for** char **in** chars {

             

            **if** char != " " {

               chars[index] = char

               index += 1

                isFirstSpace = **true**

            } **else** **if** isFirstSpace && index > 0 { // 确保不是字符串的开始

                chars[index] = char

                index += 1

                isFirstSpace = **false**

            }

        }

        

        

        **while** index > 0, chars[index-1] == " " {

            index -= 1

        }

        

        **return** String(chars.prefix(index))

        

    }

    

    

    //MARK -

    **func** reverseWord(chars:**inout** Array<Character>, start:Int, end:Int) {

         **var** left = start

         **var** right = end

        

         **while** left < right {

            chars.swapAt(left, right)

            left += 1

            right -= 1

         }

    }

}

时空复杂度分析

错误与反思

  1. split(separator:) 方法:

    • split(separator:) 是 Swift 中的一个方法,用于根据指定的分隔符将字符串分割成多个子字符串。这些子字符串会被返回为一个数组。
    • 当有连续的分隔符(例如连续的空格)时,split 会将它们视为一个单一的分隔符。因此,它可以有效地处理多余的空格。
    • 例如:"a b c".split(separator: " ") 会返回 ["a", "b", "c"]
  2. reversed() 方法:

    • reversed() 是 Swift 中的一个方法,用于反转数组的元素顺序。
    • 例如:对于数组 ["a", "b", "c"]reversed() 会返回 ["c", "b", "a"]
  3. joined(separator:) 方法:

    • joined(separator:) 是 Swift 中的一个方法,用于将一个字符串数组连接成一个单一的字符串。连接时,可以使用指定的分隔符。
    • 例如:对于数组 ["c", "b", "a"]joined(separator: " ") 会返回字符串 "c b a"

示例:

考虑以下字符串:s = " Hello World Goodbye "

  1. 使用 split(separator: " ") 方法:
let words = s.split(separator: " ")
print(words)  // 输出:["Hello", "World", "Goodbye"]

这里,多余的空格被忽略,并且只返回了实际的单词。

  1. 使用 reversed() 方法:
let reversedWords = words.reversed()
print(reversedWords)  // 输出:["Goodbye", "World", "Hello"]

这里,单词的顺序被反转了。

  1. 使用 joined(separator: " ") 方法:
let finalString = reversedWords.joined(separator: " ")
print(finalString)  // 输出:"Goodbye World Hello"

这里,反转后的单词被连接成了一个新的字符串。

综上所述,这三个方法分别用于分割、反转和连接字符串,使得可以轻松地操作和转换字符串。

二 , 常用函数

func reverse(_ chars: inout [Character], start: Int, end: Int) { 
var start = start 
var end = end 
while start < end { 
chars.swapAt(start, end) 
start += 1 
end -= 1
}
}
            } else if isFirstSpace { // 确保不是字符串的开始

这段代码的意图是只保留连续的第一个空格并跳过后续的连续空格。但是,这种方法在处理输入字符串开始处的空格时可能会出问题,因为它不会正确地跳过字符串开始的多余空格。

为了解决这个问题,我们需要在开始处理空格之前确保至少有一个非空格字符已经被处理。我们可以通过调整 isFirstSpace 的初始化值和循环内部的逻辑来实现这一点。

以下是修正后的代码:

var index = 0
var isFirstSpace = true
for char in chars {
    if char != " " {
        chars[index] = char
        index += 1
        isFirstSpace = true
    } else if isFirstSpace && index > 0 { // 确保不是字符串的开始
        chars[index] = char
        index += 1
        isFirstSpace = false
    }
}

在这里,我们添加了 index > 0 的检查,以确保我们不会在字符串的开始处添加空格。这样,我们只有在处理到第一个非空格字符后才会开始处理空格。

概念

使用场景与应用

  1. 原地操作:直接在给定的数据结构上进行操作,而不需要额外的空间。
  2. 双指针技巧:使用两个指针来追踪和操作数据,如在字符串或数组中。
  3. inout 关键字:在 Swift 中,允许函数修改传入的参数值。

应用到实际场景

  1. 文本处理:例如,在编辑器或文本处理工具中,用户可能需要对文本进行操作,如反转单词、删除多余空格等。原地操作可以提高效率,因为它不需要额外的存储空间。
  2. 数据清洗:在处理大量数据时,经常需要进行数据清洗,如删除多余的空格、标点符号等。双指针技巧可以高效地处理这种情况。

iOS app 开发的实际使用场景

  1. 搜索建议:在搜索框中,当用户开始输入时,应用可能需要快速地处理用户的输入,例如删除多余的空格或标点,然后提供相关的搜索建议。

    • 技术点:原地操作、双指针技巧
  2. 文本编辑器/笔记应用:用户可能希望有一个功能可以快速地整理和格式化他们的文本,例如反转单词或句子、删除多余的空格等。

    • 技术点:原地操作、双指针技巧、inout 关键字(Swift)
  3. 表单验证:在用户提交表单之前,应用可能需要对输入内容进行清洗和验证,如删除多余的空格、检查有效性等。

    • 技术点:原地操作、双指针技巧