来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
491.给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。
- 看到题目一顿操作写出以下代码。逐一取出数组nums中的元素放入path数组,并且要求这次取出的元素要比上次取的元素大。这代码显然犯了两个错误,一个是没有去重;还有一个是每次取出的元素不应该仅仅是比上次取的元素大,而应该是比之前所有取的元素大,因为题目要求的是递增子序列,由于题目给定的序列不一定是有序的,所以仅仅比较前一个元素是不够的。
/**
* 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().
*/
void backtracking(int* nums, int numsSize, int** res, int* returnSize, int* columnSizes, int* path, int pathSize, int startIndex, bool used) {
if (pathSize >= 2) {
res[*returnSize] = malloc(sizeof(int) * pathSize);
for (int i = 0; i < pathSize; i++) {
res[*returnSize][i] = path[i];
}
columnSizes[(*returnSize)++] = pathSize;
}
if (startIndex == numsSize)
return;
for (int i = startIndex; i < numsSize; i++) {
if (i > 0 && nums[i] < nums[i - 1])
continue;
path[pathSize++] = nums[i];
backtracking(nums, numsSize, res, returnSize, columnSizes, path, pathSize, i + 1);
pathSize--;
}
}
int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
int** res = malloc(sizeof(int*) * pow(2, numsSize));
int* columnSizes = malloc(sizeof(int) * pow(2, numsSize));
int* path = malloc(sizeof(int) * numsSize);
backtracking(nums, numsSize, res, returnSize, columnSizes, path, 0, 0);
*returnColumnSizes = malloc(sizeof(int) * (*returnSize));
for(int i = 0; i < *returnSize; i++) {
(*returnColumnSizes)[i] = columnSizes[i];
}
return res;
}
- 之前在求组合问题中,处理去重的逻辑是先将给定的序列进行排序,然后只要出现重复的数字且是在横向遍历的话,就跳过这个数字。然而本题并不能将给定的序列进行排序,因为排序完后序列的所有子序列都是递增子序列,这不符合题目的要求。因此这里自己定义了一个函数hadUsed,用来判断当前使用的数字在之前是否已经使用过了,并且还是用一个布尔型变量used用于判断当前是横向出现了重复元素还是纵向出现了重复元素,如果当前使用的数字在之前已经使用过并且是横向遍历的话,那么就跳过这个数字。
处理完去重问题之后,还要过滤一些情况,只有当前取出的数字大于等于path数组最后一个元素时,该数字才能放入path数组,因为path数组是递增的,所以path数组中暂存的序列是满足题目要求的。
所以有了以下代码:
/**
* 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().
*/
bool hadUsed(int* nums, int start, int end, int num) { //用于判断num在区间[start, end]是否出现过
if (start > end)
return false;
for (int i = start; i <= end; i++) {
if (nums[i] == num)
return true;
}
return false;
}
void backtracking(int* nums, int numsSize, int** res, int* returnSize, int* columnSizes, int* path, int pathSize, int startIndex, bool used) {
if (pathSize >= 2) { //当path数组存了两个以上数字的话就放入res数组
res[*returnSize] = malloc(sizeof(int) * pathSize);
for (int i = 0; i < pathSize; i++) {
res[*returnSize][i] = path[i];
}
columnSizes[(*returnSize)++] = pathSize;
}
if (startIndex == numsSize) //递归出口,不写也没有关系
return;
for (int i = startIndex; i < numsSize; i++) {
if (i > 0 && hadUsed(nums, startIndex, i - 1, nums[i]) && used == false) //当前在横向出现了重复元素,要跳过当前取出的数字
continue;
if (pathSize != 0 && nums[i] < path[pathSize - 1]) //当前取出的数字不满足递增子序列的要求
continue;
path[pathSize++] = nums[i];
used = true;
backtracking(nums, numsSize, res, returnSize, columnSizes, path, pathSize, i + 1, used);
//回溯
used = false;
pathSize--;
}
}
int** findSubsequences(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
*returnSize = 0;
int** res = malloc(sizeof(int*) * pow(2, numsSize));
int* columnSizes = malloc(sizeof(int) * pow(2, numsSize));
int* path = malloc(sizeof(int) * numsSize);
backtracking(nums, numsSize, res, returnSize, columnSizes, path, 0, 0, false);
*returnColumnSizes = malloc(sizeof(int) * (*returnSize));
for(int i = 0; i < *returnSize; i++) {
(*returnColumnSizes)[i] = columnSizes[i];
}
return res;
}