原题
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.
题目翻译
给定一个整数数组,如果两个数相加等于目标值,则返回它们的索引。
假定,只有一组解,同一个元素不能用两次。
代码分析1
用两个指针分析指向当前和之后,判断和是否等于目标值,代码也非常简单。
代码实现
public int[] TwoSum(int[] nums, int target)
{
for(int i=0;i<nums.Length;i++)
{
for(int j=i+1;j<nums.Length;j++)
{
if (nums[i] + nums[j] == target)
return new int[] { i, j };
}
}
return null;
}
结果分析
时间复杂度为n的平方,先换一种思路来解决这个问题,假定两个数中其中一个为i,则在i+1开始寻找另一个数target-a[i]
这个数即可。
代码实现2
public static int[] TwoSum2(int[] nums, int target)
{
for(int i=0;i<nums.Length;i++)
{
int add1 = nums[i];
int add2 = target - add1;
int add2Index = findIndex(nums, i+1,add2);
if (add2Index != -1)
return new int[] { i, add2Index };
}
return null;
}
public static int findIndex(int[] nums,int begin, int target)
{
for(int i=begin;i<nums.Length;i++)
{
if (nums[i] == target)
return i;
}
return -1;
}
但以上两个算法的时间复杂度都趋向于n的平方。有没有算法时间复杂度更小的呢?我们借用字典来使算法复杂度趋向于线性。
代码实现3
public static int[] TwoSum3(int[] nums, int target)
{
Dictionary<int, int> dict = new Dictionary<int, int>();
for(int i=0; i<nums.Length;i++)
{
if (dict.ContainsKey(target - nums[i]))
return new int[] { dict[target - nums[i]] ,i};
else
{
if(!dict.ContainsKey(nums[i])) //同一个元素不能用两次
dict.Add(nums[i], i);
}
}
return null;
}
结果测试
第三种算法 Runtime: 422 ms
,比前两种算法都快了接近30%,击败了95%的提交版本。
下面提供一种如果数组是有序数组的算法。
题目延伸
如果我们加上一个假定条件,假定数组是有序数组。根据有序数组的规律,用2个指针求解。不断调整起、终指针。
public int[] TwoSum4(int[] num, int target)
{
//因为一定存在解,所以不做边界检查
int left = 0, right = num.Length - 1;
while (left < right)
{
int v = num[left] + num[right];
if (v == target)
return new int[2] { left + 1, right + 1 };
else if (v > target)
right--;
else
left++;
}
return new int[] { };
}
}
更多参考
LeetCode-Easy部分中标签为HashTable的所有题目
leetcode-solution库
leetcode算法题目解决方案每天更新在github库中,欢迎感兴趣的朋友加入进来,也欢迎star,或pull request。https://github.com/jackzhenguo/leetcode-csharp