接上文,HJ41 称砝码
更新acd代码,牛客代码如下
#include <stdio.h>
#include <stdlib.h>
#include <string.h>int calculateWeight(int *weight, int weightLen, int *num, int numLen)
{int array[20001] = {0};int hash[300001] = {0};hash[0] = 1;int arrayIndex = 1;for(int i = 1; i <= num[0]; i++){int tempWeight = weight[0] * i;if(hash[tempWeight] == 0){array[i] = tempWeight;arrayIndex++;}hash[array[i]]++;}for(int i = 1; i < numLen; i++){int tempArrayIndex = arrayIndex;for(int j = 1; j <= num[i]; j++){for(int k = 0; k < tempArrayIndex; k++){int tempWeight = j * weight[i] + array[k];if(tempWeight < 300000 && hash[tempWeight] == 0){hash[tempWeight]++;array[arrayIndex] = tempWeight;arrayIndex++;} }}}return arrayIndex;
}int main() {return 0;int count = 0;char countStr[4] = {'\0'};while (fgets(countStr, 4, stdin) != NULL) { // 注意 while 处理多个 case// 64 位输出请用 printf("%lld") to // countStr[1] = '\0';count = atoi(&countStr[0]);int weight[count];memset(weight, 0, sizeof(weight));int num[count];memset(num, 0, sizeof(num));char weightStr[200];char numStr[200];int weightIndex = 0;int numIndex = 0;fgets(weightStr, 200, stdin);fgets(numStr, 200, stdin);int len = strlen(weightStr);weightStr[strlen(weightStr) - 1] = '\0';numStr[strlen(numStr) - 1] = '\0';char* p = strtok(weightStr, " ");while(p){weight[weightIndex++] = atoi(p);p = strtok(NULL, " ");}p = strtok(numStr, " ");while(p){num[numIndex++] = atoi(p);p = strtok(NULL, " ");}int resultArrayIndex = calculateWeight(weight, count, num, count);printf("%d", resultArrayIndex);}return 0;
}
三、
3.1 最终aced了
//aced 通过全部用例
//运行时间
//2ms
//占用内存
//1708KB
这次的代码着实搞了很久,开始是因为不知道怎么样取端所有的砝码值,然后看了别人的代码,自己也尝试写出来了。
后面就是因为获取数据的时候出问题,包括获取数量值,获取重量值字符串数组的长度、以及获取个数值字符串数组的长度。
后面就是因为array数组的长度不够、以及hash数组长度不够导致程序一直会有问题。
这次的改进就是开始使用googleTest开始进行单元测试了。其实一开始c语言课程的时候就教过,但是当时没有意识到用处。后面写trafficLight测试用例的时候意识到了重要性。这次写牛客题用了感觉确实有用。
下面是对于空间复杂度的计算
显示计算了牛客编译器int型数组的字节数,printf(“%d”, sizeof(int));打印值是4。
// int array[20001] = {0};
// int hash[300001] = {0};total = 20000 * 4 + 300000 * 4 = 1,280,000Byte = 1280KB
// 和1708KB有区别,但是接近可参考
四、后续
还要看下别人是怎么实现的
这个算法是:后面每个重量都是weight[i] * num[i] + 前面已称出的砝码。所以保留第一种所有砝码的重量,然后将后面算出的砝码都和后面的相加。
看评论好像还有路径规划的算法。
另外就是比较和c++解题的差别。c++的会更好处理数组吗?不会出现数组长度分配不够大但是有担心过度分配的问题?
2024年7月8日19:33:48
今天看了下解题思路,然后其实一开始我还纠结于想看下官方解题的,觉得里面应该有关于路径规划的视频。搞了一段时间发现没有办法找到会员,除非淘宝买会员。最后只能硬看别人的代码,发现其实好像也不难。
下面先回答上面的几个问题。
首先就是如果使用c原因其实也不用那么麻烦。
第一个就是我用fgets获取每一行字符串然后再解析的,看别人的代码,使用scanf就可以了。
第二个就是我处理起来很棘手的问题,就是关于hash数组开辟多大的值。我从一开始的1000,最后到10万都不够,真尴尬,实际看别人的代码处理的方法就很简单。就是将所有砝码的值加起来得到一个最大值。用这个值作为数组的长度。另外就是关于存在唯一的砝码重量的array的长度,其实应该也是用砝码总重量来开辟。但是其实被人根本就没有处理,只是用了一个计数器来计数,是可以这样处理的,因为不需要记录这些唯一的砝码的重量。
需要用新的方法重新处理一下代码。
更新代码如下:
#define HJ41_2024年7月8日20#ifdef HJ41_2024年7月8日20
#include <string.h>int calculateWeight(int *weight, int weightLen, int *num, int numLen)
{int totalNum = 0;for(int i = 0; i < numLen; i++){for(int j = 1; j <= num[i]; j++){totalNum += j * weight[i];}}int array[totalNum];int hash[totalNum];memset(array, 0, sizeof(array));memset(hash, 0, sizeof(hash));hash[0] = 1;int arrayIndex = 1;for(int i = 1; i <= num[0]; i++){int tempWeight = weight[0] * i;if(hash[tempWeight] == 0){array[i] = tempWeight;arrayIndex++;}hash[array[i]]++;}for(int i = 1; i < numLen; i++){int tempArrayIndex = arrayIndex;for(int j = 1; j <= num[i]; j++){for(int k = 0; k < tempArrayIndex; k++){int tempWeight = j * weight[i] + array[k];if(tempWeight < totalNum && hash[tempWeight] == 0){hash[tempWeight]++;array[arrayIndex] = tempWeight;arrayIndex++;}}}}return arrayIndex;
}#ifdef HJ41_2024年7月2日20_WITH_MAIN
int main() {int count = 0;char countStr[4] = {'\0'};while (scanf("%d",&count) != EOF) { // 注意 while 处理多个 caseint weight[count];memset(weight, 0, sizeof(weight));for(int i = 0; i <count; i++){scanf("%d", &weight[i]);}int num[count];memset(num, 0, sizeof(num));for(int i = 0; i < count; i++){scanf("%d", &num[i]);}int resultArrayIndex = calculateWeight(weight, count, num, count);printf("%d", resultArrayIndex);}return 0;
}#endif#endif
上述代码很好的解决了输入数据获取的问题。同时也很简单的解决了hash数组和array数组的问题。下面是时间空间复杂度,怎么感觉比之前的还多呢,无语。先不管这个。
通过全部用例
运行时间9ms
占用内存8832KB
2024年7月8日20:45:40
增加对上述代码的修改
其实上述代码在Clion上运行的时候是有报错的,但是我没有看出来。
[ RUN ] googleMyTest.HJ41_7
SetUp
TearDown
[ OK ] googleMyTest.HJ41_7 (1 ms)
[ RUN ] googleMyTest.HJ41_8
SetUp进程已结束,退出代码为 -1073741571 (0xC00000FD)
其实HJ41_8示例没有跑完,调试代码发现在申请array[totalNum]的时候程序进入hardFault。感觉可能栈溢出了。然后使用堆内存申请资源。
改成
int* array = (int*)malloc(sizeof(int) * totalNum);
int* hash = (int*)malloc(sizeof(int) * totalNum);
memset(array, 0, sizeof(int) * totalNum);
memset(hash, 0, sizeof(int) * totalNum);
示例正常跑完。
现在我的疑虑是为什么直接写成int array[20001] = {0};不会报错呢?
然后我再看了下值,当第8个示例时,算出来的totalNum值为1097525,远大于之前写的2w,所以会溢出。使用堆内存申请避免溢出,这也解释了为什么第二版代码的占用内存为8832KB。因为确实占用的资源很多。
然后看了别人的代码,是这样得到重量最大值的。然后对于示例八,totalNum的值是199550。确实小了不少。
for(int i = 0; i < numLen; i++)
{totalNum += (weight[i] * num[i]);
}
哎,我觉得还是做的题目太少,才手忙脚乱没处理好。
五、总结
上述是集合处理方法,还有路径规范的没有实现。