力扣491题(求递增子序列,递归、回溯)

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/increasing-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

491.给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

  1. 看到题目一顿操作写出以下代码。逐一取出数组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;
}
  1. 之前在求组合问题中,处理去重的逻辑是先将给定的序列进行排序,然后只要出现重复的数字且是在横向遍历的话,就跳过这个数字。然而本题并不能将给定的序列进行排序,因为排序完后序列的所有子序列都是递增子序列,这不符合题目的要求。因此这里自己定义了一个函数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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值