读《最发人深省的亚马逊面试题,你会如何作答?》对问题14的“1-250数字缺失”的研究

来源:互联网 发布:node throw err 编辑:程序博客网 时间:2024/05/01 05:54

闲着无事,突然翻到《最发人深省的亚马逊面试题,你会如何作答?》

http://www.csdn.net/article/2013-10-21/2817233-amazon-interview-questions


身为一个技术宅,自然对其他题目不感兴趣。只研究了第14题。

14. 这里有一串字符,从1~250的数字随机分布在其中,现在它缺少了一个号码,你会用什么办法来找到缺失的那一个?


一开始觉得挺简单,只要用一个bool bExist[250]的数组记录数字是否存在,遍历一遍,看那个缺失了就可以了。


然后就觉得似乎有些浪费内存了,其实只需要一个int变量,记录字符串的各个数字和,然后依次减去1-250,结果就会得到缺失的数字的负值。自然就出来了。


再接着,看到别人的讨论,发现似乎有人理解成数字可以连续的情况,

"1225021546172121110231114238216162203230818199761167024816325010517915243449210110714164175541361429812812418157101328842592022052241121323621091183748532936777117234212161582181561001266852305118114522015437243315218813419294182137226393821242534317822620204219123955471066124511190130171174820191462193897922899174282111502491232332062419611310422160125491641891401357863139751099719419716611922914882161137165214831081961491841873420845867316822595141121861851701691381224712787159661475716022318019111823296936352519510317658414323511515120924419810223712071227240153217232155802465617365411671901774020031144198461331292752220713162222"

我想了一下,换个思路,能不能依次检索字符串中的1-250数字,如果数字连续出现的次数为1,就删除,那么最后剩下的就是最终缺失的数字。

但编程后运行,发现最终显示的剩下的不止一个,没法继续,而且剩下的也不是我预期的丢失数字,因为预期的丢失数字字符可以被其他的数字合成。


这样继续研究,发现只能通过统计0-9字符出现的个数,计算出缺失的数字的字符组成(1-3个),后续的排除还是只能手工进行。

因为存在无法用程序逻辑确定的地方,比如连续的146,可以是1、46,可以是1、46,也可以是146。随便举出一堆的例子,121,212,各种不确定。

假如字符串是缺少46,但你不知道,你在字符中找到了46,那么你要保证没有占用以4结尾的4数字,和以6开头的6数字,这样就链式反应,各种依赖。

/* 缺某个数的字符串 */char szNumber[1024] = {0};srand((unsigned int)time(NULL));int iLost = rand() % 250 + 1;int iOffset = 0;for (int i = 1; i <= 250; ++i){if (i == iLost){continue;}iOffset += sprintf(szNumber + iOffset, "%d", i);}/* 确定1-250字符串里面0-9的数字应该出现的次数 */char szCharStatisticsStd[10] = {0};for (int i = 1; i <= 250; ++i){char szTemp[4] = {0};sprintf(szTemp, "%d", i);int iStrLen = strlen(szTemp);for (int j = 0; j < iStrLen; ++j){int iDigit = szTemp[j] - '0';++szCharStatisticsStd[iDigit];}}/* 计算给出字符串中的各数字字符出现个数 */char szCharStatisticsCurr[10] = {0};for (unsigned int i = 0; i < strlen(szNumber); ++i){if ('0' <= szNumber[i] && szNumber[i] <= '9'){int iDigit = szNumber[i] - '0';++szCharStatisticsCurr[iDigit];}}/* 提取出缺失的数字 */char szLost[4] = {0};int iLostCount = 0; /* 数字的总缺失个数 */for (int i = 0; i < 10; ++i){/* 数字的缺失个数 */int iCount = szCharStatisticsStd[i] - szCharStatisticsCurr[i];for (int j = 0; j < iCount; ++j){szLost[iLostCount] = '0' + i;++iLostCount;}}printf("Lost Digit: %c %c %c\n", szLost[0], szLost[1], szLost[2]);


当然,至少到了这一步,如果使用穷枚举,肯定能做到,试图匹配所有的数字,然后排除剩下多余1个的丢失数的结果,只使用只剩下一个丢失数的结果,就是结果了。

但这样就感觉没意思了。当然,有时候简单就是一种美。


再仔细分析,其实现实中出现这种需求,十有八九是设计问题了。简化一下逻辑,加上一个前提,就是数字与数字之间存在间隔,不会直接相连,比如:

"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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250"

那么,排除过程就变得极其简单了。


当然,这样的话,也没必要搞排除,直接计算总值,然后计算缺少的值,即可。

void FindLostNumber(void){/* 缺某个数的字符串 */char szNumber[1024] = {0};srand((unsigned int)time(NULL));int iLost = rand() % 250 + 1;int iOffset = 0;for (int i = 1; i <= 250; ++i){if (i == iLost){continue;}iOffset += sprintf(szNumber + iOffset, "%d ", i);}printf("%s\n", szNumber);/* 计算给出字符串中的各数字的值 */int iTotalSum = 0;char *pszSub = strtok(szNumber, " ");while (NULL != pszSub){iTotalSum += atoi(pszSub);pszSub = strtok(NULL, " ");}/* 减去1-250数值 */char szCharStatisticsStd[10] = {0};for (int i = 1; i <= 250; ++i){iTotalSum -= i;}iTotalSum = -iTotalSum;printf("Lost Number: %d\n", iTotalSum);}

个人浅见,随手而写,欢迎指正。



原创粉丝点击