Two Sum 非唯一元素逻辑

huangapple go评论76阅读模式
英文:

Two Sum non-unique elements logic

问题

这段代码在数组中包含唯一元素的测试用例上有效,但如果存在相同的元素,例如 [3, 2, 3],则不起作用,所以我想要类似于添加 3+3 === target(当目标为 6 时)并获取它们的索引。请解释我在这里使用的逻辑和迄今为止的方法。

function twoSum(nums, target) {
  return nums.reduce((acc, ele, index) => {
    if (ele + nums.at(index + 1) === target) {
      acc.push(index, index + 1);
    }
    return acc;
  }, []);
}

const nums = [2, 7, 11, 15];
const target = 9;

console.log(twoSum(nums, target));

const nums1 = [3, 2, 3];
const target1 = 6;

console.log(twoSum(nums1, target1));

请注意,这段代码的逻辑试图使用 reduce 方法遍历数组,并检查当前元素和下一个元素的总和是否等于目标值。如果相等,它将两个元素的索引添加到结果数组中。但是,这个方法存在问题,因为它只检查了相邻元素之间的总和,并且可能会漏掉其他组合。

要解决这个问题,可以考虑以下更改:

function twoSum(nums, target) {
  const numToIndex = {};

  for (let i = 0; i < nums.length; i++) {
    const complement = target - nums[i];
    if (numToIndex.hasOwnProperty(complement)) {
      return [numToIndex[complement], i];
    }
    numToIndex[nums[i]] = i;
  }

  return [];
}

const nums = [2, 7, 11, 15];
const target = 9;

console.log(twoSum(nums, target));

const nums1 = [3, 2, 3];
const target1 = 6;

console.log(twoSum(nums1, target1));

这个改进的方法使用一个对象 numToIndex 来存储元素与其索引之间的映射关系。它遍历一次数组,对于每个元素,计算与目标值的差值(即补数),然后检查补数是否已经在 numToIndex 对象中存在。如果存在,就返回补数的索引和当前元素的索引,从而得到答案。这种方法在时间复杂度上更有效率,因为只需一次遍历即可找到答案。

英文:

This code works for the test cases having unique elements in the array but not if the same element is present like [3,2,3] so I want something like to add 3+3 === target(when the target is 6) and to get both of their indexes. Please explain me the logic and upto this rate my approach which I used here.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function twoSum(nums, target) {
  return nums.reduce((acc, ele, index) =&gt; {
    if (ele + nums.at(index + 1) === target) {
      acc.push(index, index + 1)
    }
    return acc
  }, [])
}

const nums = [2, 7, 11, 15]
const target = 9

console.log(twoSum(nums, target))

const nums1 = [3,2,3]
const target1 = 6

console.log(twoSum(nums1, target1))

<!-- end snippet -->

答案1

得分: 1

以下是翻译好的部分:

代码部分不翻译,仅返回翻译的内容。

我们可以使用一个映射(map)并遍历数组,存储每个元素的值和索引。然后,我们检查每个元素是否其互补元素已经在映射中。如果找到了,我们遍历互补元素的索引数组,并为每个索引添加一对索引到结果中,以处理数字的重复使用。

时间复杂度仍为:O(n)

由于可能存在多个结果,单个结果也是嵌套的。如果你不喜欢这种方式,我们可以将它们展平。

这个方法看起来更加优雅,但时间复杂度为O(n^2)。

英文:

We can use a map and iterate over the array, storing each element's value and index. We then check for each element if its complement is already in the map. If found, we iterate over the array of indices for the complement, and for each index, add a pair of indices to the result to handle reuse of a digit.

Time complexity still: O(n)

Due to the possible multiple results, single results are also nested. We can flatten them if you do not like it.

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const twoSum = (nums, target) =&gt; nums.reduce((acc, ele, index) =&gt; {
  let complement = target - ele;
  if (acc.map.has(complement)) {
    for (let compIndex of acc.map.get(complement)) {
      acc.result.push([compIndex, index]);
    }
  }
  if (!acc.map.has(ele)) acc.map.set(ele, []);
  acc.map.get(ele).push(index);
  return acc;
}, { map: new Map(), result: [] }).result;


const nums = [2, 7, 11, 15]
const target = 9
console.log(twoSum(nums, target)) // Output: [0, 1]

const nums1 = [3, 2, 3]
const target1 = 6
console.log(twoSum(nums1, target1)) // Output: [0, 2]

console.log(twoSum([2, 7, 11, 7, 15, 2, 7], 9)) // [[0,1], [0,3], [0,6], [1,5], [3,5], [5,6]]

<!-- end snippet -->

This one looks more elegant but is O(n^2)

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const twoSum = (nums, target) =&gt; nums.reduce((acc, ele, i) =&gt; {
  nums.slice(i + 1).forEach((ele2, j) =&gt; {
    if (ele + ele2 === target) acc.push([i, i + j + 1]);
  });
  return acc;
}, []);

const nums = [2, 7, 11, 15]
const target = 9
console.log(twoSum(nums, target)) // Output: [0, 1]

const nums1 = [3, 2, 3]
const target1 = 6
console.log(twoSum(nums1, target1)) // Output: [0, 2]

console.log(twoSum([2, 7, 11, 7, 15, 2, 7], 9)) // [[0,1], [0,3], [0,6], [1,5], [3,5], [5,6]]

<!-- end snippet -->

答案2

得分: 0

Iterate all possible combinations of 2 elements and collect their indices:

function twoSum(nums, target) {
  const result = [];
  for (let i = 0; i < nums.length - 1; i++) {
    for (let j = i + 1; j < nums.length; j++) {
      if (nums[i] + nums[j] === target) {
        result.push([i, j]);
      }
    }
  }
  return result;
}

const log = result => console.log(JSON.stringify(result));

log(twoSum([2, 7, 11, 15], 9))
log(twoSum([2, 7, 11, 7, 15, 2, 7], 9))
log(twoSum([2, 7, 11, 15], 18))
log(twoSum([3, 2, 3], 6))

An Array::reduce() version:

function twoSum(nums, target) {
    return nums.reduce((result, num, i) => {
        return nums.slice(i + 1).reduce((result, num2, j) => {
            num + num2 === target && result.push([i, i + j + 1]);
            return result;
        }, result);
    }, []);
}

const log = result => console.log(JSON.stringify(result));

log(twoSum([2, 7, 11, 15], 9))
log(twoSum([2, 7, 11, 7, 15, 2, 7], 9))
log(twoSum([2, 7, 11, 15], 18))
log(twoSum([3, 2, 3], 6))

Benchmark with a small set:

<script benchmark data-count="1000000">

    // @benchmark mplungjan

    const twoSum2 = (nums, target) => nums.reduce((acc, ele, index) => {
        let complement = target - ele;
        if (acc.map.has(complement)) {
            for (let compIndex of acc.map.get(complement)) {
                acc.result.push([compIndex, index]);
            }
        }
        if (!acc.map.has(ele)) acc.map.set(ele, []);
        acc.map.get(ele).push(index);
        return acc;
    }, { map: new Map(), result: [] }).result;

    // @run
    [twoSum2([2, 7, 11, 15], 9),
    twoSum2([2, 7, 11, 7, 15, 2, 7], 9),
    twoSum2([2, 7, 11, 15], 18),
    twoSum2([3, 2, 3], 6)]


    // @benchmark Alexander

    const twoSum = (nums, target) => {
        const result = [];
        for (let i = 0; i < nums.length; i++) {
            for (let j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] === target) {
                    result.push([i, j]);
                }
            }
        }
        return result;
    };

    // @run
    [twoSum([2, 7, 11, 15], 9),
    twoSum([2, 7, 11, 7, 15, 2, 7], 9),
    twoSum([2, 7, 11, 15], 18),
    twoSum([3, 2, 3], 6)]

</script>

<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>

Benchmark with a big set:

<script benchmark data-count="1">

    const random = Array.from({length:20000}, () => Math.round(Math.random()*20));

    // @benchmark mplungjan

    const twoSum2 = (nums, target) => nums.reduce((acc, ele, index) => {
        let complement = target - ele;
        if (acc.map.has(complement)) {
            for (let compIndex of acc.map.get(complement)) {
                acc.result.push([compIndex, index]);
            }
        }
        if (!acc.map.has(ele)) acc.map.set(ele, []);
        acc.map.get(ele).push(index);
        return acc;
    }, { map: new Map(), result: [] }).result;

    // @run
    twoSum2(random, 9)

    // @benchmark Alexander

    const twoSum = (nums, target) => {
    
        const result = [];
        for (let i = 0; i < nums.length; i++) {
            for (let j = i + 1; j < nums.length; j++) {
                if (nums[i] + nums[j] === target) {
                    result.push([i, j]);
                }
            }
        }
        return result;
    };

    // @run
    twoSum(random, 9);

</script>

<script src="https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js"></script>
英文:

Iterate all possible combinations of 2 elements and collect their indices:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function twoSum(nums, target) {
const result = [];
for(let i = 0; i &lt; nums.length - 1; i++){
for(let j = i + 1; j &lt; nums.length; j++){
if(nums[i] + nums[j] === target){
result.push([i,j]);
}
}
}
return result;
}
const log = result =&gt; console.log(JSON.stringify(result));
log(twoSum([2, 7, 11, 15], 9))
log(twoSum([2, 7, 11, 7, 15, 2, 7], 9))
log(twoSum([2, 7, 11, 15], 18))
log(twoSum([3, 2, 3], 6))

<!-- end snippet -->

An Array::reduce() version:

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

function twoSum(nums, target) {
return nums.reduce((result, num, i) =&gt; {
return nums.slice(i + 1).reduce((result, num2, j) =&gt; {
num + num2 === target &amp;&amp; result.push([i, i + j + 1]);
return result;
}, result);
}, []);
}
const log = result =&gt; console.log(JSON.stringify(result));
log(twoSum([2, 7, 11, 15], 9))
log(twoSum([2, 7, 11, 7, 15, 2, 7], 9))
log(twoSum([2, 7, 11, 15], 18))
log(twoSum([3, 2, 3], 6))

<!-- end snippet -->

Benchmark with a small set:
Two Sum 非唯一元素逻辑
<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;script benchmark data-count=&quot;1000000&quot;&gt;
// @benchmark mplungjan
const twoSum2 = (nums, target) =&gt; nums.reduce((acc, ele, index) =&gt; {
let complement = target - ele;
if (acc.map.has(complement)) {
for (let compIndex of acc.map.get(complement)) {
acc.result.push([compIndex, index]);
}
}
if (!acc.map.has(ele)) acc.map.set(ele, []);
acc.map.get(ele).push(index);
return acc;
}, { map: new Map(), result: [] }).result;
// @run
[twoSum2([2, 7, 11, 15], 9),
twoSum2([2, 7, 11, 7, 15, 2, 7], 9),
twoSum2([2, 7, 11, 15], 18),
twoSum2([3, 2, 3], 6)]
// @benchmark Alexander
const twoSum = (nums, target) =&gt; {
const result = [];
for (let i = 0; i &lt; nums.length; i++) {
for (let j = i + 1; j &lt; nums.length; j++) {
if (nums[i] + nums[j] === target) {
result.push([i, j]);
}
}
}
return result;
};
// @run
[twoSum([2, 7, 11, 15], 9),
twoSum([2, 7, 11, 7, 15, 2, 7], 9),
twoSum([2, 7, 11, 15], 18),
twoSum([3, 2, 3], 6)]
&lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

Benchmark with a big set:
Two Sum 非唯一元素逻辑

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-html -->

&lt;script benchmark data-count=&quot;1&quot;&gt;
const random = Array.from({length:20000}, () =&gt; Math.round(Math.random()*20));
// @benchmark mplungjan
const twoSum2 = (nums, target) =&gt; nums.reduce((acc, ele, index) =&gt; {
let complement = target - ele;
if (acc.map.has(complement)) {
for (let compIndex of acc.map.get(complement)) {
acc.result.push([compIndex, index]);
}
}
if (!acc.map.has(ele)) acc.map.set(ele, []);
acc.map.get(ele).push(index);
return acc;
}, { map: new Map(), result: [] }).result;
// @run
twoSum2(random, 9)
// @benchmark Alexander
const twoSum = (nums, target) =&gt; {
const result = [];
for (let i = 0; i &lt; nums.length; i++) {
for (let j = i + 1; j &lt; nums.length; j++) {
if (nums[i] + nums[j] === target) {
result.push([i, j]);
}
}
}
return result;
};
// @run
twoSum(random, 9);
&lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月23日 20:43:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76748308.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定