检查和删除符号时字符串索引出现错误。我该如何改善?
func romanToInt(_ s: String) -> Int {
let romanDigits = ["I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000]
let romanSums = ["IV" : 4,
"IX" : 9,
"XL" : 40,
"XC" : 90,
"CD" : 400,
"CM" : 900]
var sum = 0
var str = s
var charIndex = str.startIndex
for index in str.indices {
if index != str.index(before: str.endIndex) {
charIndex = str.index(after: index)
} else {
charIndex = str.index(before: str.endIndex)
}
let chars = String(str[index]) + String(str[charIndex])
if romanSums[chars] != nil {
print(chars)
str.remove(at: charIndex)
sum += romanSums[chars]!
print(sum)
} else {
let char = String(str[index])
print(char)
sum += romanDigits[char]!
print(sum)
}
print(str)
}
return sum
}
let check = romanToInt("MCMXCIV")
控制台日志:
M 1000 MCMXCIV CM 1900 MCXCIV XC 1990 MCXIV IV 1994 MCXI Fatal error: Can't advance past endIndex
答案 0 :(得分:2)
for index in str.indices {
...
str.remove(at: charIndex)
在迭代字符串时修改字符串无效。 str.indices
在这里被提取了一次,并且在您修改了基础字符串之后不再有效。
我敢肯定会有很多实现,因为这是吸引实现的小而有趣的问题。那为什么不呢?这只是让我大叫递归。
let romanDigits: [Substring: Int] = ["I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000]
let romanSums: [Substring: Int] = ["IV" : 4,
"IX" : 9,
"XL" : 40,
"XC" : 90,
"CD" : 400,
"CM" : 900]
func romanToInt<S: StringProtocol>(_ s: S) -> Int
where S.SubSequence == Substring {
if s.isEmpty { return 0 }
if let value = romanSums[s.prefix(2)] {
return value + romanToInt(s.dropFirst(2))
} else if let value = romanDigits[s.prefix(1)] {
return value + romanToInt(s.dropFirst(1))
} else {
fatalError("Invalid string")
}
}
let check = romanToInt("MCMXCIV")
当然,这实际上并不检查有效的序列,因此有点垃圾。 “ IIIIXXIII”有点乱码,但是可以用。但这与原始方法保持一致。
答案 1 :(得分:2)
您正在修改要迭代的字符串,因此索引无效。相反,您可以添加一个skipChar
布尔值,表示您已经处理了下一个字符,然后通过执行continue
跳过该字符:
func romanToInt(_ s: String) -> Int {
let romanDigits = ["I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000]
let romanSums = ["IV" : 4,
"IX" : 9,
"XL" : 40,
"XC" : 90,
"CD" : 400,
"CM" : 900]
var sum = 0
var str = s
var charIndex = str.startIndex
var skipChar = false
for index in str.indices {
if skipChar {
skipChar = false
continue
}
if index != str.index(before: str.endIndex) {
charIndex = str.index(after: index)
} else {
charIndex = str.index(before: str.endIndex)
}
let chars = String(str[index]) + String(str[charIndex])
if romanSums[chars] != nil {
print(chars)
skipChar = true
sum += romanSums[chars]!
print(sum)
} else {
let char = String(str[index])
print(char)
sum += romanDigits[char]!
print(sum)
}
print(str)
}
return sum
}
let check = romanToInt("MCMXCIV")
print(check)
1994
答案 2 :(得分:1)
使用reduce
使它在此处流动:
func romanToInt(_ s: String) -> Int {
if s.isEmpty {return 0}
let romanDigits = ["I" : 1,
"V" : 5,
"X" : 10,
"L" : 50,
"C" : 100,
"D" : 500,
"M" : 1000]
let romanSums = ["IV" : 4,
"IX" : 9,
"XL" : 40,
"XC" : 90,
"CD" : 400,
"CM" : 900]
return s.dropFirst().reduce((s.first!, romanDigits["\(s.first!)"]!)){
return ( $1, //current char
$0.1 + //previous sum
(romanSums["\($0.0)\($1)"] //add double value
?? ((romanDigits["\($1)"]!). + romanDigits["\($0.0)"]!)) //or single value and add duplicated
- romanDigits["\($0.0)"]!) // minus duplicated
}.1
}
print(romanToInt("MCMXCIV")). //1994
答案 3 :(得分:0)
您正在循环内对str
进行突变,其结束索引将发生变化,在这种情况下,它的值低于其原始值。您可以使用while循环,通过检查每次迭代的循环次数是否未超过endIndex
来修正代码:
var index = str.startIndex
while index < str.endIndex {
...
//Before the closing curly brace of the while loop
index = str.index(after: index)
}
答案 4 :(得分:0)
我试图重现我的用户报告的崩溃,并显示相同的消息Can't advance past endIndex
,但我无法做到。您的代码帮助我弄清楚了该错误在swift的更高版本中已更改。
您的相同代码将使用快速的4.x运行时库报告cannot increment beyond endIndex
,并使用5.x报告String index is out of bounds
。我不知道更改的确切版本号。但我怀疑它是4.0.0和5.0.0。-