LeeCode 40.组合总和II

给定一个候选人编号的集合 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的每个数字在每个组合中只能使用 一次

**注意:**解集不能包含重复的组合。

示例 1:

复制代码
输入: candidates = [10,1,2,7,6,1,5], target = 8,
输出:
[
[1,1,6],
[1,2,5],
[1,7],
[2,6]
]

示例 2:

复制代码
输入: candidates = [2,5,2,1,2], target = 5,
输出:
[
[1,2,2],
[5]
]

提示:

  • 1 <= candidates.length <= 100
  • 1 <= candidates[i] <= 50
  • 1 <= target <= 30

答案如下:

cpp 复制代码
void zuhe2(int target, int idx, int* temp, int tempSize
	, int** res, int*** pRes, int* returnSize, int** returnColumnSizes, int* pCapacity, int* numCountMap);

/**
 * Return an array of arrays of size *returnSize.
 * The sizes of the arrays are returned as *returnColumnSizes array.
 * Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
 */
int** combinationSum2(int* candidates, int candidatesSize, int target, int* returnSize, int** returnColumnSizes) { // LeetCode 40.组合和总和
        // 先统计数组中每个数的出现个数。由题意 1 <= candidates[i] <= 50, numCountMap[n]表示n在candidates数组中出现的次数
    int numCountMap[51] = { 0 };
    for (int i = 0; i < candidatesSize; i++) {
        numCountMap[candidates[i]]++;
    }
    // 1 <= target <= 30 , 而数组candidates中的数最小为1,所以组合子数组长度最大可能为30
    // 但是不知道组合数量,所以结果数组大小不确定。
    int tempCapacity = candidatesSize < 30 ? candidatesSize : 30;
    int* temp = (int*)malloc(tempCapacity * sizeof(int)); 
    if (!temp) return NULL;
    *returnSize = 0;
    int capacity = 2; // 初始容量,后续容量不够再扩容

    *returnColumnSizes = (int*)malloc(capacity * sizeof(int));
    int** res = (int**)malloc(capacity * sizeof(int*));
    if (!res) return NULL;
    zuhe2(target, 0, temp, 0, res ,&res ,returnSize, returnColumnSizes, &capacity, numCountMap);
    free(temp);
    return res;
}

void zuhe2(int target, int idx, int* temp, int tempSize
	, int** res, int*** pRes, int* returnSize, int** returnColumnSizes, int* pCapacity, int* numCountMap) {
	if (target == 0) {
		// 已满足,保存结果
		int* arr_ = (int*)malloc(tempSize * sizeof(int));
		if (!arr_) return;
		memcpy(arr_, temp, tempSize * sizeof(int));
		// 保存前先检查容量
		if (*returnSize == *pCapacity) { // 之前申请的内存满了,不够再存储了,扩容
			int newCapacity = *pCapacity << 1;
			int** temp_res = (int**)realloc(res, newCapacity * sizeof(int*));
			if (!temp_res) return;
			*pRes = temp_res;

			*returnColumnSizes = (int*)realloc(*returnColumnSizes, newCapacity * sizeof(int));
			if (*returnColumnSizes == NULL) return;

			*pCapacity = newCapacity;
		}

		*(*pRes + *returnSize) = arr_;
		*(*returnColumnSizes + *returnSize) = tempSize; // 该组合的数字个数
		*returnSize = *returnSize + 1;
		return;
	}
	for (int i = idx; i < 51; i++) {
		// 先判断i是否使用过了
		if (numCountMap[i] == 0) {
			// 该数使用完了
			continue;
		}
		if (i > target) {
			break;
		}
		// 可以加的情况,选中该数
		temp[tempSize++] = i;
		numCountMap[i]--;
		// 再递归选给临时数组下一位赋值。 注意,这里idx参数值必选传i,不能传idx,防止选到重复的组合。组合的临时数组中当前在选的数还可以选,但前面选过的数不能再选
		zuhe2(target - i, i, temp, tempSize, res, pRes, returnSize
			, returnColumnSizes, pCapacity, numCountMap);
		// 回退,不选这个数了
		tempSize--;
		numCountMap[i]++;
	}
}

测试代码:

cpp 复制代码
void testLeeCode40(void) { // 组合总和II
	int nums[] = { 4,4,2,1,4,2,2,1,3 };
	int target = 6;
	int numsSize = sizeof(nums) / sizeof(int);
	int returnSize; // 用于接受结果二维数组的长度。
	int* returnColumnSizes; // 用来接受结果二维数组的每个元素(即子数组)的长度
	int** res = combinationSum2(nums, numsSize, target, &returnSize, &returnColumnSizes);
	printArr(res, returnSize, returnColumnSizes); // 打印二维数组

	// 释放内存
	for (int i = 0; i < returnSize; i++) {
		free(res[i]);
	}
	free(res);
	free(returnColumnSizes);
}

运行:

ok. 但是提交到LeeCode,报错:

看上去是调用realloc函数时报错重复释放内存了。 但是没看出来哪里重复释放内存了。没懂这个报错哪来的,我自己机器上没报错。怎么办? 我把二维数组的容量直接设置为1000,1000应该是够用了,避免了动态扩容数组,提交通过了:

这个疑问点后面再研究。

相关推荐
彦为君24 分钟前
算法思维与经典智力题
java·前端·redis·算法
智能优化与强化学习34 分钟前
Gym(Gymnasium)仿真环境详解(二):环境简介、入门算法、调参要点、核心挑战
算法·强化学习·gym·零基础入门·算法评估
mxwin1 小时前
Unity Shader exp 函数的算法与渲染应用
算法·unity·游戏引擎·shader
“码”力全开1 小时前
AI视频分析误报优化完整流程
算法·架构·边缘计算
深盾科技_Virbox1 小时前
深盾科技·Virbox产品体系全景解读:软件安全如何从加密锁走向全生命周期
java·大数据·算法·安全·软件需求
可编程芯片开发1 小时前
基于VSG虚拟同步发电机控制的三相并网逆变器带多组可变负载Simulink建模与仿真
算法
AI服务老曹2 小时前
国产NPU视觉算法参数配置说明
算法·性能优化·边缘计算
彦为君2 小时前
Redis最新版本特性
java·数据库·redis·算法·bootstrap
触底反弹2 小时前
🔥 字符串算法面试三连击:反转、回文、回文变种,搞懂这三题稳了!
前端·javascript·算法
aaaameliaaa3 小时前
计算斐波那契数(递归、迭代)(1,1,2,3,5.....)
c语言·开发语言·笔记·算法·排序算法