題目是這樣的,已知一個整數數列(這里應該說的是正整數數列)和一個給定的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);
}
}
}
}
代碼寫得有點拙劣,望廣大博友批評指導!希望有人能提出更好的方案哈!