记一道面试题

题目是这样的,已知一个整数数列(这里应该说的是正整数数列)和一个给定的sum值,从这个整数数列中,找出两个整数的和刚好等于sum值,将这个数列中所有这种可能的组合进行输出。

例如:有一个整数数列{3,4,2,7,5,2,4},sum=6,

那么这样的组合就有:

第二项和第三项的和,即<2,3>;

第二项和第六项的和,即<2,6>;

第三项和第七项的和,即<3,7>;

以此类推…

 

当时我的解答是这样,比较笨哈:

 

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

namespace ConsoleApplication16
{
class Program
{
static void Main(string[] args)
{
int[] testArray = { 3, 4, 2, 7, 5, 2, 4 };
Console.WriteLine(GetNumCombinations(testArray,6));
}

public static string GetNumCombinations(int[] arrayInt, int sum)
{
List<int> firstNums = new List<int>();
List<int> secondNums = new List<int>();

for (int i = 0; i < arrayInt.Length-1; i++)
{
for (int j = i+1; j < arrayInt.Length; j++)
{
if (arrayInt[i]+arrayInt[j]==sum)
{
firstNums.Add(i+1);
secondNums.Add(j + 1);
}
}
}

StringBuilder sb = new StringBuilder();

for (int i = 0; i < firstNums.Count; i++)
{
sb.Append(String.Format("<{0},{1}>",firstNums[i],secondNums[i]));
}

return sb.ToString();
}
}
}

 

这里有两个问题,第一个问题就是采用List来保存配对的元素。List的内部顺序是不稳定的,也就是说,你先Add进去的元素并不一定会在后Add进去的元素前面,所以,有可能会造成配对的信息错误。(这个问题其实我没考证过,是那个面试官这么解释的,大致意思我猜想就是这样)所以应该自定义一个数据结构进行保存。

 

还有一个问题就是算法的效率问题了,具体差在哪?一看就懂得哈!

面试官给了我一个方案,先对数列进行一个从小到大的排序,找sum,和sum/2在数列中的位置,然后再循环查找。

 

回来后总结了一下,我想他的大致意思应该是这样的:

继续拿上面得例子演示,先将数列进行排序。

 

2,2,3,4,4,5,7

 

当然,顺序乱了,之前的序列值肯定也不对了,所以需要多增加一个数组来维护它的序列值,就假如它排序后的序列值如下:

 

2,2,3,4,4,5,7

3,6,1,2,7,5,4(这一行是序列值)

 

然后找到sum和sum/2在该序列中的位置,sum=6,sum/2=3:

 

2,2,3,(3),4,4,5,(6),7

 

相信大部分人应该看出名堂了吧,想要两个数的和相加等于6,那么这两个数必定有一个小于3,另一个大于3,不可能有两个数都大于3的数相加小于等于6的,同理,也不可能有两个数都小于3的数相加大于等于6的。

 

在取数据进行相加的时候,设一个变量x从最小值到中间值,一个变量y从最大值到中间值:

 

→x                ←y

2,2,3,(3),4,4,5,(6),7

 

如果两数相加比sum大,那么最大值y肯定更小,如果两数相加比sum小,那么最小值x需要更大,直到x与y到中间值为止。

 

代码重新整理如下(咱就不考虑排序的效率了哈,也没有很好的容错性,应该会有各种BUG哈,呵呵!)

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

namespace ConsoleApplication17
{
//保存配对信息
struct NumCombin
{
public int x;
public int y;

public override string ToString()
{
return String.Format("<{0},{1}>", x, y);
}
}

class Program
{
public static NumCombin[] GetNumCombinations(int[] arrayInt, int sum)
{
List<NumCombin> numCombinList = new List<NumCombin>();

//创建一个数组维护排序顺序
int[] arrayOrder = new int[arrayInt.Length];
for (int i = 0; i < arrayOrder.Length; i++)
{
arrayOrder[i] = i + 1;
}

//一个简单的冒泡,进行从小到大的排序
for (int i = 0; i < arrayInt.Length; i++)
{
bool isChange = false;

for (int j = 0; j < arrayInt.Length-1-i; j++)
{
if (arrayInt[j]>arrayInt[j+1])
{
int temp = arrayInt[j];
arrayInt[j] = arrayInt[j + 1];
arrayInt[j + 1] = temp;

temp = arrayOrder[j];
arrayOrder[j] = arrayOrder[j + 1];
arrayOrder[j + 1] = temp;

isChange = true;
}
}

if (!isChange)
{
break;
}
}

int maxCount=-1, halfCount=-1;

for (int i = 0; i < arrayInt.Length; i++)
{
if (arrayInt[i]>sum)
{
maxCount = i;
break;
}
}

if (maxCount==-1)
{
maxCount = arrayInt.Length;
}

for (int i = 0; i < arrayInt.Length; i++)
{
if (arrayInt[i]>sum/2)
{
halfCount = i;
break;
}
}

//如果这个数列最大的数都没有达到sum值的一半,
//那么肯定不会存在两个数相加为sum的值
if (halfCount==-1)
{
return null;
}

for (int i = 0; i < halfCount; i++)
{
for (int j = maxCount; j >= halfCount; j--)
{
if (arrayInt[i] + arrayInt[j] > sum)
{
maxCount--;

}
else if (arrayInt[i] + arrayInt[j] < sum)
{
break;
}
else
{
NumCombin numCombin = new NumCombin() { x = arrayOrder[i], y = arrayOrder[j] };
numCombinList.Add(numCombin);
}
}
}

return numCombinList.ToArray();
}

static void Main(string[] args)
{
NumCombin[] test = GetNumCombinations(new int[] { 3, 4, 2, 7, 5, 2, 4 },6);

foreach (var item in test)
{
Console.WriteLine(item);
}

}
}
}

 

 

 

代码写得有点拙劣,望广大博友批评指导!希望有人能提出更好的方案哈!

posted @ 2012-02-29 23:19  heqichang  阅读(2236)  评论(32编辑  收藏  举报