### LeetCode 1. Two Sum

LeetCode 的第 1 題 "Two Sum"，題目描述如下。

LeetCode 第一題題目解釋：給一整數陣列 nums 與一整數 target，假設剛好有一對 nums[i] + nums[j] == target，回傳 int[]{ i, j }

## Step 1, 新增失敗測試案例，Test_nums_is_1_8_and_target_is_9_should_return_0_1

        [TestMethod]
public void Test_nums_is_1_8_and_target_is_9_should_return_0_1()
{
var sut = new Solution();
var nums = new int[] { 1, 8 };
var target = 9;

var expected = new int[] { 0, 1 };

var actual = sut.TwoSum(nums, target);

CollectionAssert.AreEqual(expected, actual);
}

hard-code 以通過測試的生產代碼：

    public class Solution
{
public int[] TwoSum(int[] nums, int target)
{
return new int[] { 0, 1 };
}
}

## Step 2, 重構測試程式，擷取出 TwoSum() 與 ShouldEqual() 兩個方法

    [TestClass]
public class UnitTest1
{
[TestMethod]
public void Test_nums_is_1_8_and_target_is_9_should_return_0_1()
{
var nums = new int[] { 1, 8 };
var actual = TwoSum(nums, 9);

var expected = new int[] { 0, 1 };
ShouldEqual(expected, actual);
}

private static int[] TwoSum(int[] nums, int target)
{
var actual = new Solution().TwoSum(nums, target);
return actual;
}

private static void ShouldEqual(int[] expected, int[] actual)
{
CollectionAssert.AreEqual(expected, actual);
}
}

## Step 3, 新增失敗測試案例，Test_nums_is_1_2_4_and_target_is_5_should_return_0_2

        [TestMethod]
public void Test_nums_is_1_2_4_and_target_is_5_should_return_0_2()
{
var nums = new int[] {1, 2, 4};
var actual = TwoSum(nums, 5);

var expected = new int[] {0, 2};
ShouldEqual(expected, actual);
}

## Step 5, 重構演算法，先排序，以減少第二層迴圈巡覽次數

        public int[] TwoSum(int[] nums, int target)
{
var sorted = nums
.Select((x, index) => Tuple.Create(x, index))
.OrderBy(x => x.Item1).ToArray();

for (int i = 0; i < sorted.Length; i++)
{
for (int j = i + 1; j < sorted.Length; j++)
{
var twoSum = sorted[i].Item1 + sorted[j].Item1;
if (twoSum == target)
{
return new int[] { Math.Min(sorted[i].Item2, sorted[j].Item2), Math.Max(sorted[i].Item2, sorted[j].Item2) };
}

if (twoSum > target)
{
break;
}
}
}

return null;
}

## Step 6, 重構演算法，不用兩層迴圈

        public int[] TwoSum(int[] nums, int target)
{
var sorted = nums
.Select((x, index) => Tuple.Create(x, index))
.OrderBy(x => x.Item1).ToArray();

var start = 0;
var end = sorted.Length - 1;
while (start < end)
{
if (sorted[start].Item1 + sorted[end].Item1 == target)
{
return new int[] { Math.Min(sorted[start].Item2, sorted[end].Item2), Math.Max(sorted[start].Item2, sorted[end].Item2) };
}
else if (sorted[start].Item1 + sorted[end].Item1 < target)
{
start++;
}
else
{
end--;
}
}

return null;
}

## 更新1: 改以 Dictionary<int, int> 存放巡覽過的值，只需一次迴圈

        public int[] TwoSum(int[] nums, int target)
{
var dictionary = new Dictionary<int, int>();
for (int i = 0; i < nums.Length; i++)
{
var key = target - nums[i];
if (dictionary.ContainsKey(key))
{
return new int[] { dictionary[key], i };
}
else if (!dictionary.ContainsKey(nums[i]))
{
}