3
\$\begingroup\$

Program description:

Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target. You may assume that each input would have exactly one solution, and you may not use the same element twice. You can return the answer in any order.

My solution:

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function(nums, target) {
  let N = nums.length;  
  for(i=0;i<=N-1;i++) {
      for(j=i+1;j<=N;j++) {
          if(nums[i] + nums[j] == target) {
              return [i,j];
          };
      };
  };  
};

Test input:

[2,7,11,15]
9

Test output:

[0,1]

Test summary:

Solution accepted.
Runtime: 84ms

Question: is there a way to make this code look more neat using some comprehensions, maybe also improving its runtime? Thank you in advance.

\$\endgroup\$
2
  • 2
    \$\begingroup\$ Welcome to Code Review! The current question title, which states your concerns about the code, is too general to be useful here, since most posts pos the question of how the code can be simplified. Please edit to the site standard, which is for the title to simply state the task accomplished by the code. Please see How do I ask a good question?, as well as How to get the best value out of Code Review: Asking Questions for guidance on writing good question titles. \$\endgroup\$ Commented Nov 2, 2020 at 15:47
  • \$\begingroup\$ There is a tag 2sum - and probably more questions tackling twosum without it than tagged. \$\endgroup\$
    – greybeard
    Commented Nov 3, 2020 at 5:43

1 Answer 1

3
\$\begingroup\$

Performance The biggest issue with your current implementation is that it's O(n ^ 2). You have to iterate through an array of length N (N ^ 2) / 2 times in order to find matches. The algorithm can be improved by iterating only once, and by using a Set or an object when iterating to store which number the current number would have to be paired with in order to sum to the target.

For example, when iterating over 1, with a target of 5, you could put 4 into the Set, because 1 + 4 === 5. On further iterations, check to see if the element being iterated over exists in the Set. If it does, it's a match: return the pair. See bottom of answer for an implementation.

Prefer const over let Since N isn't being reassigned, declare it with const: https://softwareengineering.stackexchange.com/questions/278652/how-much-should-i-be-using-let-vs-const-in-es6

Don't create global variables Always declare variables before using them. Your current code with for(i=0;i<=N-1;i++) and for(j=i+1;j<=N;j++) { is implicitly creating global i and j variables. This is both inelegant and can lead to confusing bugs if the function gets called again before its first call completes. (Also consider adding spaces between operators for readability). You'd want to do:

for (let i = 0; i < N; i++) {

Note the use of i < N, not i <= N; since N is the length, nums[N] will be undefined, so you shouldn't iterate over it.

Use strict equality Don't use == - it has many strange rules with type coercion. Even if you're sure the types of the operands are the same, to make it clearer for readers at a glance, better to avoid it and use === or !== instead.

/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
const twoSum = function(nums, target) {
  // Key: Number which, if found, matches the number at the index value
  // eg: { 3 => 6 }: if 3 is found later, it'll be a match with the number at index 6
  const indexByPair = new Map();
  const { length } = nums;
  for (let i = 0; i < length; i++) {
    if (indexByPair.has(nums[i])) {
      return [indexByPair.get(nums[i]), i];
    }
    indexByPair.set(target - nums[i], i);
  }
};
console.log(twoSum([2,7,11,15], 9));

\$\endgroup\$
2
  • \$\begingroup\$ Thank you so much for the detailed answer \$\endgroup\$ Commented Nov 2, 2020 at 17:50
  • \$\begingroup\$ Note the use of i < N, not i <= N which doesn't occur in the question - you correctly quoted i=0;i<=N-1. Then again, your warning against accessing nums[N] is spot-on, and a measure against it has to be taken - the limit in the nested loop has to be lowered: for (let j = i + 1; j < N; j++). (The outer loop doesn't need a limit at all: 1) it doesn't index nums (movement of code evaluating "invariant expressions" exempted - a beast to debug) 2) a value will be returned before i exceeds any promising limit given You may assume that each input would have exactly one solution.) \$\endgroup\$
    – greybeard
    Commented Dec 13, 2020 at 7:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.