问题分析
这道题目要求我们从一个字符串中提取所有连续的数字子串,并计算它们的总和。需要注意以下两点特殊要求:
- 支持负数处理:遇到’-'且后面跟着数字时,将该数字视为负数
- 忽略小数点:数字间的小数点(如"1.1")应被视为连续的数字"11"
例如:
- 输入:
"aA1BDSK1.1DF"
→ 输出:1 + 11 = 12
- 输入:
"dn12DGSs-3dgdc--1xDS"
→ 输出:12 + (-3) + 1 = 10
解题思路
- 遍历字符串:逐个字符检查
- 状态管理:
- 使用
inNumber
标记是否正在处理数字 - 使用
negative
标记当前数字是否为负数
- 使用
- 特殊字符处理:
- 遇到’-':若不在数字处理中,标记
negative=true
;否则作为普通字符处理 - 遇到’.':直接忽略(视为数字的一部分)
- 遇到’-':若不在数字处理中,标记
- 边界处理:
- 字符串末尾可能是数字,需要特殊处理
- 处理多位数(如"123")和前导零(如"007")
Golang代码实现
下面是Golang语言的实现方案:
package main
import (
"fmt"
"unicode"
)
// sumNumericSubstrings 计算字符串中所有数字子串的和(支持负数和忽略小数点)
func sumNumericSubstrings(s string) int {
total := 0 // 总和
currentNum := 0 // 当前正在处理的数字
inNumber := false // 是否正在处理数字
negative := false // 当前数字是否为负数
for i, char := range s {
if unicode.IsDigit(char) {
// 遇到数字
if !inNumber {
// 开始新的数字
inNumber = true
currentNum = int(char - '0') // 字符转数字
} else {
// 继续构建当前数字
currentNum = currentNum*10 + int(char-'0')
}
} else if char == '-' {
// 遇到负号
if !inNumber {
// 如果不在数字处理中,标记为负数
negative = true
} else {
// 如果正在处理数字,将当前数字累加到总和,然后开始新的负数
if negative {
total -= currentNum
} else {
total += currentNum
}
currentNum = 0
negative = true
}
} else if char == '.' {
// 遇到小数点,直接忽略(视为数字的一部分)
continue
} else {
// 遇到其他非数字字符
if inNumber {
// 当前数字结束,根据negative标记决定加减
if negative {
total -= currentNum
} else {
total += currentNum
}
inNumber = false
currentNum = 0
negative = false
}
// 重置负号标记(如果不在数字处理中)
negative = false
}
// 处理字符串最后一个字符是数字的情况
if i == len(s)-1 && inNumber {
if negative {
total -= currentNum
} else {
total += currentNum
}
}
}
return total
}
func main() {
// 测试示例
fmt.Println(sumNumericSubstrings("aA1BDSK1.1DF")) // 输出: 12
fmt.Println(sumNumericSubstrings("dn12DGSs-3dgdc--1xDS")) // 输出: 10
// 更多测试用例
fmt.Println(sumNumericSubstrings("abc")) // 输出: 0
fmt.Println(sumNumericSubstrings("123456")) // 输出: 123456
fmt.Println(sumNumericSubstrings("a007b012")) // 输出: 19
fmt.Println(sumNumericSubstrings("--12--3.4--5")) // 输出: 12 + 34 + 5 = 51
fmt.Println(sumNumericSubstrings("a-1.2b-3c-4.5")) // 输出: -12 + (-3) + (-45) = -60
}
算法复杂度分析
- 时间复杂度:O(n),其中n是字符串的长度。我们只需要遍历字符串一次。
- 空间复杂度:O(1),只使用了常数级别的额外空间。
代码解析
状态管理:
inNumber
:标记是否正在处理数字negative
:标记当前数字是否为负数
特殊字符处理:
- 负号(‘-’):如果在数字处理前遇到,标记为负数;如果在数字处理中遇到,将当前数字累加到总和,然后开始新的负数
- 小数点(‘.’):直接忽略,视为数字的一部分
边界处理:
- 字符串末尾是数字时,需要将最后一个数字累加到总和
- 连续多个负号的情况(如"–1"),只有最后一个负号会影响数字的正负性
测试用例说明
"aA1BDSK1.1DF"
→ 1 + 11 = 12(小数点被忽略,数字连续)"dn12DGSs-3dgdc--1xDS"
→ 12 + (-3) + 1 = 10(支持负数和连续负号)"--12--3.4--5"
→ 12 + 34 + 5 = 51(连续负号和小数点的组合)"a-1.2b-3c-4.5"
→ -12 + (-3) + (-45) = -60(多个负数和小数点)
总结
这个算法题主要考察字符串处理和状态机设计的能力。通过一次遍历,我们可以高效地识别并累加所有数字子串,同时处理负数和忽略小数点。关键在于清晰定义状态转换逻辑,并妥善处理各种边界情况。