LeetCode 494. 目标和

110 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目:给定一个整数数组nums和一个目标target。要求向数组中每个整数前面加+-,之后串联所有整数得到一个表达式,该表达式的值等于target

解题思路

因为只有两种字符,因此我们可以遍历全部的可能,为每个字符前面都尝试+-,之后判断是否到达末尾并且target满足条件即可,可得代码如下:

public int findTargetSumWays(int[] nums, int target) {
    return find(nums, 0, target);
}

public int find(int[] nums, int index, int target) {
    if(target == 0 && index == nums.length) return 1;
    if(index==nums.length) return 0;

    int l = find(nums, index+1, target+nums[index]);
    int r = find(nums, index+1, target-nums[index]);

    return l + r;
}

思路显然是没问题的,但最后超时了,把代码修改成下面的:

private int res = 0;
public int findTargetSumWays(int[] nums, int target) {
    return find(nums, 0, target);
}
public void find2(int[] nums, int index, int target) {
    if(index==nums.length){
        if(target == 0){
            res++;
        }
        return;
    }

    find2(nums, index+1, target+nums[index]);
    find2(nums, index+1, target-nums[index]);
}

成功AC,可能是因为递归相加比较耗时,最后要一层层的返回。但最后的耗时也是558ms,算是险过吧。

思路进阶(01背包)

本题还可以转换成01背包的问题,具体可看 LeetCode 416.分割等和子集

二维数组表示动态转移数组代码如下:

public int findTargetSumWays(int[] nums, int target) {
    int sum = 0;
    for (int num : nums) {
        sum += num;
    }
    int weight = (target + sum) >> 1;
    if(weight<0) return 0;
    if((target + sum) % 2 != 0) return 0;
    int[][] dp = new int[nums.length+1][weight + 1];
    // 背包容量为weight
    // 每个物品的重量为nums,现要将物品刚好填满背包
    // dp[i][j] 背包容量为j时,物品0-i可填满背包的组合有多少
    for(int i=0;i<=nums.length;i++) dp[i][0] = 1; // 所有物品放入容量为0的背包种数(都不放)
    for(int i=1;i<=nums.length;i++){
        for(int j=0;j<=weight;j++){
            if(j>=nums[i-1]){
                dp[i][j] = dp[i-1][j] + dp[i-1][j-nums[i-1]];
            }else {
                dp[i][j] = dp[i-1][j];
            }
        }
    }
    return dp[nums.length][weight];
}

空间优化后代码如下,所需要注意的还是背包容量的遍历顺序:

public int findTargetSumWays(int[] nums, int target) {
    int sum = 0;
    for (int num : nums) {
        sum += num;
    }
    int weight = (target + sum) >> 1;
    if(weight<0) return 0;
    if((target + sum) % 2 != 0) return 0;
    int[] dp = new int[weight + 1];
    dp[0] = 1;

    for(int i=0;i<nums.length;i++){
        for(int j=weight;j>=nums[i];j--){
            dp[j] = dp[j] + dp[j-nums[i]];
        }
    }
    return dp[weight];
}

LeetCode 461.汉明距离

穿插一个简单题:计算两个整数的汉明距离。

直接说怎么做了,汉明距离实际上就是统计两个数异或后二进制中1的个数,我们可以直接用内置函数:

Integer.bitCount(x^y);

还可以自己统计,用计算数的二进制方法,除2取余法,如果找到余数为1的则直接count,代码如下:

public int hammingDistance(int x, int y) {
    int num = x^y;
    int count = 0;
    while(num/2!=0||num%2!=0){
        if(num % 2 == 1) count++;
        num = num / 2;
    }
    return count;
}