字符串问题——字符串中数字子串求和

题目:给定一个字符串str,求其中全部数字串所代表的数字之和。
要求:忽略小数点子,如”A1.3”包含两个数字1和3.
如果紧贴数字子串左边出现”-“,如果连续出现奇数个则视为负,如果连续出现偶数个则视为正。如”A-1BC–12”其中包含数字-1和-12。
例:A1CE2E33,返回36。

实现:如何从左至右遍历str时,准确地收集每个数字并加起来。时间复杂的O(N),额外空间复杂度O(1)。
1.设置3个变量。rst表示目前的累加和;num表示当前收集到的数;布尔型变量sign表示num加到rst中是正还是负数。
2.对于cha是’0’~’9’的数字字符,设当前字符cur=cha-‘0’,之前收集的数字位num。
例如str=”123”,当cha=’1’,num=1,当cha=’2’,num=12,当cha=’3’,num=123。
例如str=”-123”,初始时num=0,sign=true。当cha=’-‘,posi变为false。当cha=’1’,num=-1,当cha=’2’,num=-12,当cha=’3’,num=-123。
即num=num*10+(sign?cur:-cur)。
3.对于cha是非数字字符,说明前一个数字已经遍历完,直接rst+=num,然后收集数字的变量重置num=0。累加完后,
1)如果cha!=’-‘(即即不为数字,也不为’-‘),则sign=true;
2)如果cha=’-‘,则看cha的前一个字符是否为’-‘,如果是,则sign=!sign(注意这里没有直接true,因为’-‘符号个数可能大于2),否则sign=’false’。
4.由于上面是当遇到非数字字符时对rst进行累加,当字符串后面出现的是数字时,由于已经跳出了循环体,为了防止数字累加不上的情况,需要最后进行一次rst+=num。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public class NumSum {
public static int numSum (String str) {
if (str == null || str.length() == 0) {
return 0;
}
int rst = 0; //累加最终结果
int num = 0; //收集当前数字
boolean sign = true; //为正则设为true
char[] cha = str.toCharArray();
for (int i = 0; i < str.length(); i++) {
int cur = cha[i] - '0';
if (cha[i] < '0' || cha[i] > '9') { //如果不是数字
rst += num; //则对之前收集的数字进行累加
num = 0; //每加了一次num,则要把收集数字的num重置为0
if (cha[i] == '-') {
if (cha[i-1] == '-' && i-1>-1) { //如果前面还有'-',则取反
sign = !sign;
} else { //否则就一个'-',则符号为负
sign = false;
}
} else { //如果是非数字、非'-'的其它符号,依然是取正号
sign = true;
}
} else { //否则为数字,用num收集数字
num = num * 10 + (sign ? cur : -cur); //如果为正数则直接加,如果cur前面有负号,则数字cur加-
}
}
//防止最后的数字加漏。
//若最后不为数字,这一步不会对结果有影响,因为如果最后不为数字,则之前num依然在循环体里面,会用到循环里面的累加。
//此时num又被重置为0了,加了不会对rst有影响。
rst += num;
return rst;
}
//Test
public static void main(String[] args) {
String str = "A-1BC--12A";
System.out.println(numSum(str));
}
}