我正试图通过解决面试问题来学习敏捷。我要解决的问题之一如下。
给出一个字符串S和一个字符串T,找到S中包含复杂度为O(n)的T中所有字符的最小窗口。
Example:
Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"
我的实现如下,其中包含t
个字符串字符及其从s
中检索到的相应索引。
func minimumWindowSubstring(_ s: String, _ t: String) -> String{
let sChar = [Character](s)
let tChar = [Character](t)
var indexTemp = [[Character:Int]()]
for tc in tChar
{
for (j, sc) in sChar.enumerated()
{
if sc == tc
{
indexTemp.append([tc:j])
}
}
}
return ""
}
indexTemp数组中的内容如下
现在,我想知道如何才能使用此数组来找到最小窗口,我被卡住了。
答案 0 :(得分:0)
我认为这是一个有趣的问题,所以我给了一个机会。我没有使用字典,而是使用一个简单的类来存储找到的字符范围,以及一个String
来存储未找到的字符。
它只能通过一次主字符串,因此应该为O(n)。
您可以在操场上运行它。
(我知道您在修复代码方面需要帮助,但我的答案没有做到这一点,但我希望它能为您提供足够的见解来调整您自己的代码)
import Foundation
let string = "ADOBECODEBANC"
let sub = "ABC"
// Create a class to hold the start and end index of the current search range, as well as a remaining variable
// that will store which characters from sub haven't been found
class Container {
var start: Int
var end: Int?
var remaining: String
// Consume will attempt to find a given character within our remaining string, if it has found all of them,
// it will store the end index
func consume(character: Character, at index: Int) {
// If remaining is empty, we're done
guard remaining != "" else { return }
// We're assuming that sub won't have repeating characters. If it does we'll have to chage this
remaining = remaining.replacingOccurrences(of: String(character), with: "")
if remaining == "" {
end = index
}
}
init(start: Int, remaining: String) {
self.start = start
self.remaining = remaining
}
}
// ClosedContainer is similar to Container, but it can only be initialized by an existing container. If the existing
// container doesn't have an end value, the initialization will fail and return nil. This way we can weed out containers
// for ranges where we didn't find all characters.
class ClosedContainer {
let start: Int
let end: Int
init?(container: Container) {
guard let end = container.end else { return nil }
self.start = container.start
self.end = end
}
var length: Int {
return end - start
}
}
var containers = [Container]()
// Go through each character of the string
string.enumerated().forEach { index, character in
// Look for matches in sub
if sub.contains(character) {
// Allow each existing container to attempt to consume the character
containers.forEach { container in
container.consume(character: character, at: index)
}
// Create a new container starting on this index. It's remaining value will be the sub string without the
// character we just found
let container = Container(start: index, remaining: sub.replacingOccurrences(of: String(character), with: ""))
containers.append(container)
}
}
// Convert Containers into ClosedContainers using compactMap, then find the one with the shortest length
let closedContainers = containers.compactMap(ClosedContainer.init)
let maybeShortest = closedContainers.min { $0.length < $1.length }
if let shortest = maybeShortest {
// Convert int to String indices
let start = string.index(string.startIndex, offsetBy: shortest.start)
let end = string.index(string.startIndex, offsetBy: shortest.end)
// Get the result string
let result = string[start...end]
print("Shortest substring of", string, "that contains", sub, "is", result)
} else {
// No range was found that had all characters in sub
print(string, "doesn't contain all characters in", sub)
}