C#中两个整数元组的总和

时间:2015-11-13 10:14:22

标签: c# sum tuples

我正在尝试解决这个问题,就像准备面试一样: 编写一个函数,给定一个列表和一个目标和,返回任何两个不同元素的从零开始的索引,这两个元素的总和等于目标总和。如果没有这样的元素,函数应该返回null。

例如,FindTwoSum(new List(){1,3,5,7,9},12)应返回以下任何索引元组:

1,4(3 + 9 = 12)

2,3(5 + 7 = 12)

3,2(7 + 5 = 12)

4,1(9 + 3 = 12)

这是我到目前为止所做的事情

public static Tuple<int, int> FindTwoSum(List<int> list, int sum)
    {
        List<Tuple<int, int>> ListOfInt = new List<Tuple<int, int>>();
        for (int i=0; i<list.Count; i++)
        {
            for(int j=0; j<list.Count; j++)
            {
                if (list[i] + list[j] == sum)
                {
                    ListOfInt.Add(new Tuple<int, int>(i,j));
                }
            }
        }

        foreach ( var elemt in ListOfInt)
        {
            return elemt;
        }
        return null;

    }

问题是找到所有结果并保存在元组中:但我仍然无法将结果打印到控制台。我认为foreach声明中有一些错误。 在我编写的主要方法中,将结果打印到控制台:

Console.WriteLine(FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12));

请问任何建议:)?

8 个答案:

答案 0 :(得分:5)

好吧,如果a + b = sum然后b + a = sum,那么你可以切断内循环并立即返回两对;您当前实现的另一个问题和计数器示例a + a = sum不计,例如。

  {3, 6, 9}, 12

应仅返回

  0, 2 // 3 + 9
  2, 0 // 9 + 3

而不是

  1, 1 // 6 + 6 is wrong

我宁愿实现返回IEnumerable<Tuple<int, int>>的解决方案:

  // Are you given List<int>? What about int[]? IEnumerable<int> is a much better choice 
  public static IEnumerable<Tuple<int, int>> FindTwoSum(IEnumerable<int> items, int sum) {
    // Validate Arguments (the method is public one!)
    if (null == items)
      throw new ArgumentNullException("items");

    var list = items.ToList();

    for (int i = 0; i < list.Count - 1; ++i)   // last line doesn't count
      for (int j = i + 1; j < list.Count; ++j) // note j = i + 1
        // if ((list[i] + list[j] == sum) && (list[i] != list[j])) { // distinct values and indexes
        if (list[i] + list[j] == sum) { // distinct indexes only
          yield return new Tuple<int, int>(i, j);
          yield return new Tuple<int, int>(j, i);                
        }
  }

如果您想要不同的值以及不同的索引条件而不是

  if (list[i] + list[j] == sum)

应该是

  if ((list[i] + list[j] == sum) && (list[i] != list[j]))

不同的,但不是索引不是一种情况,因为a[i] == a[i]所以每当索引不同时都不区分值。我们有条件

  if ((list[i] + list[j] == sum) && (list[i] != list[j]))

测试:

  // note that I can pass an array (int[]) or list (List<int>) whatever collection
  String report = String.Join(Environment.NewLine, 
    FindTwoSum(new int[] { 1, 3, 5, 7, 9 }, 12));

  // (1, 4)
  // (4, 1)
  // (2, 3)
  // (3, 2)
  Console.Write(report);

答案 1 :(得分:2)

将方法的返回值更改为IEnumerable<Tuple<int, int>>,然后使用yield return返回值。当您在循环中枚举结果时(在Main()方法中),您将获得该值。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication13
{
    class Program
    {
        static void Main(string[] args)
        {
            var output = FindTwoSum(new List<int>() { 1, 3, 5, 7, 9 }, 12);
            foreach (var x in output)
                Console.WriteLine(x.Item1 + " " + x.Item2);

            Console.ReadKey(true);
        }

        public static IEnumerable<Tuple<int, int>> FindTwoSum(List<int> list, int sum)
        {
            List<Tuple<int, int>> ListOfInt = new List<Tuple<int, int>>();
            for (int i = 0; i < list.Count; i++)
            {
                for (int j = 0; j < list.Count; j++)
                {
                    if (list[i] + list[j] == sum)
                    {
                        ListOfInt.Add(new Tuple<int, int>(i, j));
                    }
                }
            }

            foreach (var elemt in ListOfInt)
            {
                yield return elemt;
            }

        }
    }
}

答案 2 :(得分:2)

考虑到问题的措辞,我注意到你的例子中存在一个潜在的问题。您提到了不同的元素,但您似乎没有采取任何措施来确保您使用的值是不同的。您似乎也能够对相同的元素求和(i == j)!。

下面的解决方案展示了如何避免上述问题,以及避免在出现时将元素放入列表中:

public static Tuple<int, int> FindTwoSum(int[] collection, int sum)
{
    int[] distinct = collection.Distinct().ToArray();
    for (int x = 0; x < distinct.Length; x++)
    {
        for (int y = 0; y < distinct.Length; y++)
        {
            if (y != x && distinct[x] + distinct[y] == sum)
                return Tuple.Create(Array.IndexOf(collection, distinct[x]), Array.IndexOf(collection, distinct[y]));
        }
    }
    return null;
}

然后您可以使用以下方式打印此结果:

Tuple<int, int> result = FindTwoSum(new[] { 1,3, 5, 7, 9}, 12);
if (result != null)
    Console.WriteLine(result.Item1 + "," + result.Item2);
else
    Console.WriteLine("No solution!");

答案 3 :(得分:2)

如果你想获得幻想,你可以使用Linq:

var numbers = new List<int> {1, 3, 5, 7, 9};

int target = 12;
var items = numbers.Select((value, index) => new {index, value});

var hits = 
    from a in items
    from b in items
    where (a.index != b.index) && (a.value + b.value == target)
    select new {index1 = a.index, index2 = b.index};

Console.WriteLine(string.Join("\n", hits.Select(x => 
    $"{x.index1}, {x.index2} ({numbers[x.index1]} + {numbers[x.index2]} = {target})")));

工作原理

首先使用numbers.Select((value, index) => new {index, value});将数字列表转换为[value,index]元组序列。

然后通过执行

有效地对该元组序列进行双循环
from a in items
from b in items

从元组序列中生成所有项目组合。

然后,它使用where过滤掉所有具有相同索引的项目(使用(a.index != b.index),并确定哪些总和与目标值匹配(使用(a.value + b.value == target))。

接下来,它会将结果选择为包含属性index1index2的新元组。

最后,它使用string.Join()输出该元组的结果。

答案 4 :(得分:1)

此部分将在找到列表中的第一个元素后立即返回。

    foreach ( var elemt in ListOfInt)
    {
        return elemt;
    }

您需要返回List<Tuple<int, int>>,然后在消费代码循环中打印出Item1Item2

答案 5 :(得分:1)

我是那些LINQish粉丝之一。所以我刚用LINQ方法编写了函数:

private static IEnumerable<Tuple<int, int>> FindTwoSum(IEnumerable<int> candidates, int expectedSum)
{
    return candidates.SelectMany((Lhs, LhsIndex) => candidates.Select((Rhs, RhsIndex) => new { Rhs, RhsIndex }).Where(r => r.RhsIndex != LhsIndex).Select(r => new { Lhs, r.Rhs }))
                        .Where(pair => pair.Lhs + pair.Rhs == expectedSum)
                        .Select(pair => Tuple.Create(pair.Lhs, pair.Rhs));
}

困难的部分是在第一步中创建所有配对。我只是为索引获取每个值,然后为索引不同的所有组合创建对。之后,很容易简单地检查它们是否总和到预期值并为输出创建所需的元组。

要调用此方法,只需使用:

var results = FindTwoSum(new[] { 1, 3, 5, 7, 9 }, 12);

foreach (var tuple in results)
{
    Console.WriteLine(tuple);
}

答案 6 :(得分:0)

这个循环:

    foreach ( var elemt in ListOfInt)
    {
        return elemt;
    }

永远不会&#34;循环&#34;背部。在第一次迭代中,如果列表中有第一个元素,它将退出并放弃循环return

如果你真的只想要第一个好的一对,那就去掉List<>

public static Tuple<int, int> FindTwoSum(List<int> list, int sum)
{
    for (int i=0; i<list.Count; i++)
    {
        for(int j=0; j<i; j++)
        {
            if (list[i] + list[j] == sum) // may want to append:   && list[i] != list[j]
            {
                return Tuple.Create(j, i);
            }
        }
    }
    return null;
}

你想在返回的元组中允许i == j吗? (编辑:更改了我自己的代码以禁止这样做。)您不必同时搜索i > ji < j,因此请选择其中一个(如上所述)。

如果您想制作新的Tuple.Create,可以使用Tuple<,>

答案 7 :(得分:0)

要从元组中读取值,请调用.Item1,.Item2等。

var myTuple = new Tuple<int, string, string>(123, "Cat", "Dog");

var id = myTuple.Item1;
var pet1 = myTuple.Item2;
var pet2 = myTuple.Item3;