Skip to content

1755. Closest Subsequence Sum

Description

You are given an integer array nums and an integer goal.

You want to choose a subsequence of nums such that the sum of its elements is the closest possible to goal. That is, if the sum of the subsequence's elements is sum, then you want to minimize the absolute difference abs(sum - goal).

Return the minimum possible value of abs(sum - goal).

Note that a subsequence of an array is an array formed by removing some elements (possibly all or none) of the original array.

 

Example 1:

Input: nums = [5,-7,3,5], goal = 6
Output: 0
Explanation: Choose the whole array as a subsequence, with a sum of 6.
This is equal to the goal, so the absolute difference is 0.

Example 2:

Input: nums = [7,-9,15,-2], goal = -5
Output: 1
Explanation: Choose the subsequence [7,-9,-2], with a sum of -4.
The absolute difference is abs(-4 - (-5)) = abs(1) = 1, which is the minimum.

Example 3:

Input: nums = [1,2,3], goal = -7
Output: 7

 

Constraints:

  • 1 <= nums.length <= 40
  • -107 <= nums[i] <= 107
  • -109 <= goal <= 109

 

Solutions

Solution: Depth-First Search + Binary Search

  • Time complexity: O(n*2n/2)
  • Space complexity: O(2n/2)

 

JavaScript

js
/**
 * @param {number[]} nums
 * @param {number} goal
 * @return {number}
 */
const minAbsDifference = function (nums, goal) {
  const n = nums.length;
  const half = Math.floor(n / 2);
  const lNums = nums.slice(0, half);
  const rNums = nums.slice(half, n);
  let lSums = new Set();
  let rSums = new Set();
  let result = Number.MAX_SAFE_INTEGER;

  const getSums = (values, index, sum, sums) => {
    if (index >= values.length) {
      sums.add(sum);
      return;
    }
    const value = values[index];

    getSums(values, index + 1, sum, sums);
    getSums(values, index + 1, sum + value, sums);
  };

  getSums(lNums, 0, 0, lSums);
  getSums(rNums, 0, 0, rSums);
  lSums = [...lSums];
  rSums = [...rSums].sort((a, b) => a - b);

  const findFirstGreaterEqual = (sums, target) => {
    let left = 0;
    let right = sums.length - 1;

    while (left <= right) {
      const mid = Math.floor((left + right) / 2);

      sums[mid] >= target ? (right = mid - 1) : (left = mid + 1);
    }

    return left;
  };

  for (const sum of lSums) {
    const index = findFirstGreaterEqual(rSums, goal - sum);

    if (index < rSums.length) {
      result = Math.min(Math.abs(goal - sum - rSums[index]), result);
    }

    if (index > 0) {
      result = Math.min(Math.abs(goal - sum - rSums[index - 1]), result);
    }
  }

  return result;
};

Released under the MIT license