力扣算法题-416.分割等和子集 C语言实现

题目

给定一个只包含正整数的非空数组。是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。

注意:
每个数组中的元素不会超过 100
数组的大小不会超过 200

示例 1:
输入: [1, 5, 11, 5]
输出: true
解释: 数组可以分割成 [1, 5, 5] 和 [11].

示例 2:
输入: [1, 2, 3, 5]
输出: false

解释: 数组不能分割成两个元素和相等的子集.

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/partition-equal-subset-sum

思路

1、动态规划二维;数组a[i][j] 表示0-i范围内的数可否有和为j;i [0,数据长度),j [0, 数组和/2];
图解详见:动态规划二维
2、动态规划一维;数组a[i] 表示是否会存在和为i, i [0, 数组和/2] ;
图解详见:动态规划一维
3、递归DFS;(这个方法提交超出了时间限制,仅提供个思路)

程序

动态规划二维

bool canPartition(int* nums, int numsSize){
    int i,j,max = 0,total=0,sum = 0;
    for(i=0;i<numsSize;i++){
        total+=nums[i];
        if(nums[i] > max){
            max = nums[i];
        }
    }
    if(total%2 != 0 || numsSize < 2 || max > total/2){
        return false;
    }else{
        sum = total/2;
        int** a=(int**)malloc(sizeof(int*)*numsSize);
        a[0] = (int*)malloc(sizeof(int)*(sum+1));
        memset(a[0],0,sizeof(int)*(sum+1));
        a[0][nums[0]] = 1;
        for(i=1;i<numsSize;i++){
            a[i]=(int*)malloc(sizeof(int)*(sum+1));
            memset(a[i],0,sizeof(int)*(sum+1));
            a[i][0] = 1;
            for(j=1;j<sum+1;j++){
                if(j>=nums[i]){
                    a[i][j] = a[i-1][j] | a[i-1][j-nums[i]];
                }else{
                    a[i][j] = a[i-1][j];
                }
            }
        }
        return a[numsSize-1][sum];
    }
    return false;
}

动态规划一维

bool canPartition(int* nums, int numsSize){
    int i,j,ibgn=0,max = 0,total=0,sum = 0;
    for(i=0;i<numsSize;i++){
        total+=nums[i];
        if(nums[i] > max){
            max = nums[i];
        }
    }
    if(total%2 != 0 || numsSize < 2 || max > total/2){
        return false;
    }else{
        sum = total/2;
        short* a=(short*)malloc(sizeof(short)*(sum+1));
        memset(a, 0, sizeof(short)*(sum+1));
        a[0] = 1;
        for(i=0;i<numsSize;i++){
            if(ibgn+nums[i] > sum){
                ibgn = sum - nums[i];
            }
            for(j=ibgn;j>=0;j--){
                a[j+nums[i]] |= a[j];
            }
            ibgn+=nums[i];
            if(a[sum]){
                return true;
            }
        }
    }
    return false;
}

递归DFS

int cmp(const void *a, const void *b){
    return *(int*)b - *(int*)a;
}
bool dfs(int* nums, int numsSize, int ibgn, int idiff)
{
    for (int j = ibgn; j < numsSize; ++j) {
        if (idiff == nums[j]) {
            return true;
        } else if (idiff > nums[j]) {
            if (dfs(nums, numsSize, j + 1, idiff - nums[j])) {
                return true;
            }
        }
    }
    return false;
}
bool canPartition(int* nums, int numsSize){
    int sum = 0;
    qsort(nums, numsSize, sizeof(int), cmp);
    for (int i = 0; i < numsSize; ++i) {
        sum += nums[i];
    }
    if (numsSize < 2 || sum%2 != 0 || sum/2 < nums[0]) {
        return false;
    }
    return dfs(nums, numsSize, 0, sum/2);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值