给定一个整数数组 nums 和一个整数目标值 target
请你在该数组中找出 “和”为目标值target的那两个整数
并返回它们的数组下标
规则:
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。你可以按任意顺序返回答案。
示例1:
输入:nums = [2, 7, 11, 15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回[0, 1]
示例2:
输入:nums = [3, 2, 4], target = 6
输出:[1,2]
示例3:
输入:nums = [3, 3], target = 6
输出:[0,1]
using System;
using System.Diagnostics;
namespace ConsoleApp2
{
internal class Program
{
/// <summary>
/// 思路:
/// 每个人一个号码,官方表示数字相加为固定数字的一对人可以获得奖励
/// 官方让找出相加是 target 15的
/// 小明手中号码是1,其他人分别是小红3,小刚5,小吕7,小紫8
/// 你是小明,你怎么去找
/// 方法1:最费力的,就是每个人都去挨个找能与他配对的,小明去找了剩下n-1个人,没找到,小红找剩下的n-2个人,没找到,。。。直到结束
/// 这样时间复杂度是o(n²)
/// 时间多在哪了?
/// 那就是没有喊话,小明如果可以喊话,告诉其他人,自己想要的是14号,别人直接能听到,就能直接知道小明能不能配对成功
///
/// 这就需要一个留声机,小明在里面留声,我是x号,我需要target-x号,
/// 然后小红先去听听有没有别人找自己,没有的话自己也去留声(注意听得过程其实就是查找,如果用数组类型的结构,可以直接在O(1)内找到)
/// 依次往后
///
/// 可以选择数组(数组有弊端,就是需要开辟空间过大,不知道应该开辟多少),或者字典等等非链表结构的去存储
/// </summary>
/// <param name="nums"></param>
/// <param name="target"></param>
/// <returns></returns>
static int[] TwoSum(int[] nums, int target)
{
int[] array = new int[2];
for (int i = 0; i < nums.Length; i++)
{
for (int j = i+1; j < nums.Length; j++)
{
if (nums[i]+nums[j] == target)
{
array[0] = i;
array[1] = j;
}
}
}
return array;
}
/// 时间多在哪了?
/// 那就是没有喊话,小明如果可以喊话,告诉其他人,自己想要的是14号,别人直接能听到,就能直接知道小明能不能配对成功
///
/// 这就需要一个留声机,小明在里面留声,我是x号,我需要target-x号,
/// 然后小红先去听听有没有别人找自己,没有的话自己也去留声(注意听得过程其实就是查找,如果用数组类型的结构,可以直接在O(1)内找到)
/// 依次往后
///
/// 可以选择数组(数组有弊端,就是需要开辟空间过大,不知道应该开辟多少),或者字典等等非链表结构的去存储
// 数组(不严谨,主要看下面字典)
static int[] TwoSum2(int[] nums, int target)
{
int[] array = new int[2];
int[] array2 = new int[100000];
for (int i = 0; i < 100000; i++)
{
array2[i] = 0;
}
for (int i = 0; i < nums.Length; i++)
{
if (array2[nums[i]] > 0)
{
array[0] = i;
array[1] = array2[nums[i]];
return array;
}
array2[target - nums[i]] = i;
}
return array;
}
/// 时间多在哪了?
/// 那就是没有喊话,小明如果可以喊话,告诉其他人,自己想要的是14号,别人直接能听到,就能直接知道小明能不能配对成功
///
/// 这就需要一个留声机,小明在里面留声,我是x号,我需要target-x号,
/// 然后小红先去听听有没有别人找自己,没有的话自己也去留声(注意听得过程其实就是查找,如果用数组类型的结构,可以直接在O(1)内找到)
/// 依次往后
///
/// 可以选择数组(数组有弊端,就是需要开辟空间过大,不知道应该开辟多少),或者字典等等非链表结构的去存储
//字典
static int[] TwoSum3(int[] nums, int target)
{
int[] array = new int[2];
// 留声机
Dictionary<int, int> dir = new Dictionary<int, int>();
for (int i = 0; i < nums.Length; i++)
{
// 在留声机中听听是否有人找过自己
if (dir.ContainsKey(nums[i]))
{
array[0] = i;
array[1] = dir[nums[i]];
return array;
}
// 如果没有任何找过自己,那就把自己要找的和自己的联系方式留进去
// 并且 因为可能两个人拿的是同一个号码,题目只让找出其中的一份就行,所以在这加入限制,留声机内存在寻找x号的了,就不用再存进去新的了
// key为自己要找的人,value是自己的联系方式,不能反,反了就无法利用O(1)的特性了
if (!dir.ContainsKey(target - nums[i]))
{
dir.Add(target - nums[i],i);
}
}
return array;
}
static void Main(string[] args)
{
int[] array = TwoSum3(new int[] {1,1,1,1,1,4,1,1,1,1,1,7,1,1,1,1,1},11);
// int[] array = TwoSum3(new int[] {1,1,1,1,3},4);
foreach (var value in array)
{
Console.WriteLine((value));
}
}
}
}
注意
类似于数组、字典一类的结构是直接访问地址查询数据的,查询时间是O(1)的,因此将想要查询的数当做字典的key,是常用的一种减少时间复杂度的关键