목표 및 leetcode (494)

목표 및 leetcode (494)

주제 링크

주제 설명

정수 배열 숫자와 정수 대상이 주어집니다.

배열의 각 정수에 '+' 또는 '-'를 추가한 다음 모든 정수를 연결하여 식을 구성합니다.

예를 들어 nums = [2, 1], 2 앞에 '+'를 추가하고 1 앞에 '-'를 추가한 다음 결합하여 "+2-1" 표현식을 얻을 수 있습니다.
대상으로 평가되는 위의 메서드로 구성할 수 있는 고유한 식의 수를 반환합니다.

예 1

입력: nums = [1,1,1,1,1], 목표 = 3
출력: 5
설명: 최종 목표 합계를 3으로 만드는 방법에는 5가지가 있습니다.
-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3


예 2

입력: 숫자 = [1], 대상 = 1
출력: 1

강제

  • 1 <= 숫자.길이 <= 20
  • 0 <= 숫자[i] <= 1000
  • 0 <= 합계(숫자[i]) <= 1000
  • -1000 <= 대상 <= 1000

아이디어(동적 프로그래밍)

아이디어 1

dp 배열은 2차원이며 dp[i][j]는 처음 i개의 숫자가 결합되어 j를 생성할 때 가능한 모든 종을 나타냅니다.

j를 형성하는 첫 번째 i 숫자는 다음과 같이 간주될 수 있습니다. 첫 번째 i - 1 숫자 형식(j - nums[i]) 더하기 nums[i] 또는 첫 번째 i - 1 숫자 형식(j + nums[i]) 빼기 nums [나]

따라서 상태 전이 방정식 dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]]


nums[i]의 값 범위는 [0, 1000]이고 target의 값 범위는 [-1000, 1000]입니다.

nums[i] = 1000일 때, dp[i][-1000]은 dp[i-1][-2000]과 dp[i-1][0]으로 구성될 수 있습니다.

dp[i][1000]은 dp[i-1][0] 및 dp[i-1][2000]에서 구성할 수 있습니다.

따라서 j의 범위는 -2000에서 2000까지입니다.

배열이 범위를 벗어나는 것을 방지하려면 int[][] dp = new int[nums.length][4001]


코드 1

class Solution {
    
    
     // 0,1 背包是取和不取 这道题是 取正和取负
    public int findTargetSumWays(int[] nums, int target) {
    
    
        // dp的第二维 取值范围为[-2000,2000]跨度为4000
        int[][] dp = new int[nums.length][4001]; // dp[i][j] 表示前i个物品组合成j+2000的可能性的种数
        // 状态转移方程感觉是个递归 dp[i][j] = dp[i-1][j-nums[i]] + dp[i-1][j+nums[i]]
        dp[0][nums[0] + 2000] += 1;
        dp[0][-nums[0] + 2000] += 1; //因为如果是0 的话 取正取负 和为0就有两种
        for (int i = 1; i < nums.length; i++) {
    
    
            for (int j = nums[i]; j<=4000-nums[i]; j++) {
    
    //这里要注意判别,防止越界
                dp[i][j] = dp[i - 1][j - nums[i]] + dp[i - 1][j + nums[i]];
            }
        }
        return dp[nums.length - 1][target + 2000];
    }
}

참고: 코드의 8-9행에서 = 대신 +=를 사용하십시오. nums[i] =0일 때 양수와 음수가 모두 0이지만 두 가지 방법이 있기 때문입니다.


아이디어 2

각 번호에 대해 두 가지 옵션이 있습니다. (1) 부호를 양수로 만들기 (2) 부호를 음수로 만들기

따라서 우리의 선택에 따라 두 더미로 나눌 수 있습니다.

양수로 선택한 수 묶음의 합을 pos로 하고, 음수로 선택한 수 묶음의 합을 음수로 합니다.

모든 숫자의 합은 합계이고 대상은 대상입니다.

다음과 같은 표현이 있습니다:
{ neg + pos = sum ( 1 ) pos − neg = target ( 2 ) \left\{ \begin{aligned} neg +pos & = sum &(1)\\ pos - neg & = target &(2) \\ \end{aligned} \right.{ 부정 _ _+p o sp o s-_ _=_=목표 _ _ _ _ _( 1 )( 2 )
用(1)+(2)得2 ∗ pos = sum + target 2 *pos = sum + target2p o s=_+목표 _ _ _ _ _

따라서 이 문제를 여러 숫자에서 임의의 숫자를 취하여 합이 ( sum + target ) / 2 (sum + target)/2가 되도록 할 수 있습니다.( _ _+t a r g e t ) / 2 . 총 몇 가지 방법이 있습니까?

코드 2

class Solution {
    
    
    public int findTargetSumWays(int[] nums, int target) {
    
    
        int sum = 0;
        for (int num : nums) {
    
    
            sum += num;
        }
        if ((target + sum) % 2 != 0) return 0; // target + sum 不能被 2 整除,表示无法选数构成pos

        int pos = Math.abs((sum + target) / 2);
        int[] dp = new int[pos + 1]; // dp[i]表示 从中 nums中取任意个数,能构成 i 的种数
        dp[0] = 1;
        for (int i = 0; i < nums.length; i++) {
    
    
            for (int j = pos; j >= nums[i]; j--) {
    
    
                dp[j] += dp[j - nums[i]];
            }
        }
        return dp[pos];
    }
}

Guess you like

Origin blog.csdn.net/jiaweilovemingming/article/details/124388345