字符串的组合个数
2014-12-12 19:35 李涛的技术博客 阅读(779) 评论(0) 编辑 收藏 举报有一个MAP,KEY从a到z,对应的VALUE从1到26,比如:
a = 1
b = 2
...
z = 26,对于一个数字字符串"11",可以由"aa"对应的数字组合,也可以由"k"对应的数字代表,对应组合的个数记为2;同样,比如"111"对应的组合个数是3,分别是"aaa", "ka", "ak"。
给定一个数字数组,计算对应的组合个数。
解答:对于一个字符串,定义f(x)为前x个字符的组合个数,那么:
f(x) = f(x-2) if 最后一个数字是'0'
= f(x-1) else if (倒数第二个数字是'0' || 最后两个数大于"26")
= f(x-1)+f(x-2) else
int last2num(char* arr, int len) { assert(arr != NULL && len >= 2); int num = (arr[len-2]-'0')*10 + (arr[len-1]-'0'); if (num <= 26) return 2; else return 1; } int countKind(char* arr, int len) { if (arr == NULL || len <= 0) return 0; if (len == 1) return 1; if (len == 2) { if (arr[len-1] == '0' || last2num(arr, len) > 26) return 1; else return 2; } if (arr[len-1] == '0') return countKind(arr, len-2); else if (arr[len-2] == '0' || last2num(arr, len) > 26) return countKind(arr, len-1); else return countKind(arr, len-1) + countKind(arr, len-2); }
另一种写法:
上面用的递归,countKind有重复计算,一种方法是把计算过的保存在一个数组里,计算是查一下,如果算过,直接返回结果;另一种方法是从0开始顺序计算,代码如下:
int last2num(char* arr, int len) { assert(arr != NULL && len >= 2); return 10*(arr[len-2]-'0') + (arr[len-1]-'0'); } int countKind(char* arr, int len) { if (arr == NULL || len <= 0) return 0; if (len == 1) return 1; else if (len == 2) { if (arr[len-1] == '0' || last2num(arr, len) > 26) return 1; else return 2; } int cnt[len+1]; cnt[0] = 0; cnt[1] = 1; if (arr[1] == '0' || last2num(arr, 2) > 26) cnt[2] = 1; else cnt[2] = 2; for (int i = 3; i <= len; i++) { if (arr[i-1] == '0') arr[i] = arr[i-2]; else if (arr[i-2] == '0' || last2num(arr, 2) > 26) arr[i] = arr[i-1]; else arr[i] = arr[i-1] + arr[i-2]; } return arr[len]; }
长度等于2的单独计算是必要的,为了解决类似"70"这样的case。