题目描述
给定一个整数数组
n
u
m
s
nums
nums 和一个目标值
t
a
r
g
e
t
target
target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
输出示例:
给定
n
u
m
s
=
[
2
,
7
,
11
,
15
]
,
t
a
r
g
e
t
=
9
nums = [2, 7, 11, 15], target = 9
nums=[2,7,11,15],target=9
因为
n
u
m
s
[
0
]
+
n
u
m
s
[
1
]
=
2
+
7
=
9
nums[0] + nums[1] = 2 + 7 = 9
nums[0]+nums[1]=2+7=9
所以返回
[
0
,
1
]
[0, 1]
[0,1]
思路1
非常自然能够想到的一种思路是:两个嵌套的 f o r for for循环。
- 第一个循环从 0 0 0开始遍历 n u m s nums nums,记每次得到 n u m s [ i ] nums[i] nums[i];
- 内嵌的第二个 f o r for for循环从 i + 1 i+1 i+1开始遍历 n u m s nums nums,记每次得到 n u m s [ j ] nums[j] nums[j];
- 每一步判断 n u m s [ i ] + n u m s [ j ] nums[i]+nums[j] nums[i]+nums[j]是否等于 t a r g e t target target,等于则直接返回。
这种思路实现简单,但时间复杂度稍高为 o ( n 2 ) o(n^2) o(n2)。
代码
def twoSum(nums, target):
for i in range(len(nums)):
for j in range(i + 1, len(nums)):
sum = nums[i] + nums[j]
if sum == target:
return [i, j]
return []
思路2——逼夹法
假如数组为有序的情况,分别将指针
i
i
i和
j
j
j指向数组首位,那么我们可以通过当前和
t
m
p
S
u
m
=
n
u
m
s
[
i
]
+
n
u
m
s
[
j
]
tmpSum=nums[i]+nums[j]
tmpSum=nums[i]+nums[j]与
t
a
r
g
e
t
target
target的关系进行有目的地移动
i
i
i和
j
j
j:小于目标值,
i
i
i自增;大于目标值
j
j
j自减。这便是逼夹法。
由于nums并不是有序的,那么需要先对数组进行一次
o
(
n
log
(
n
)
)
o(n\log(n))
o(nlog(n))的排序,再利用逼夹法,显而易见逼夹法的时间复杂度为
o
(
n
)
o(n)
o(n),所以整体复杂度也就是
o
(
n
log
(
n
)
+
n
)
o(n\log(n)+n)
o(nlog(n)+n)。
*注意:原题需要返回原数组下标,实际上只用逼夹是不合适的,因为得到的下标是排序后的数组下标,但该方法是能够获得相应的数值组合的。
代码
def twoSum(self, nums, target):
nums.sort() # 从小到大排序
i = 0 # 头指针
j = len(nums) - 1 # 尾指针
result = []
while True: # 一直循环直至i>=j
sum = nums[i] + nums[j]
if sum == target: # 假如和便是目标
result.append([i, j]) # 记录结果
# 确定下一轮的指针
ii = i + 1
while ii < j and nums[ii] == nums[i] : # 跳掉重复的
ii += 1
i = ii
jj = j - 1
while jj > i and nums[jj] == nums[j]: # 跳掉重复的
jj -= 1
j = jj
elif sum > target: # 假如过大,j向前移动,即减少和
j -= 1
else: # 假如过小,i向后移动,即增加和
i += 1
if i >= j: # 逼夹跳出条件
break
return result
参考
- [1] leetcode原题
- [2] 详尽源码