3Sum Smaller
要点:类似的题还有lintcode的triangle count
- i,j,k的规律:i:最外层,每走一步,j要重新来过,j第二层,起始为i+1,k初始取决于题目。主要利用了:
- [j,k]之间的增序:当k满足条件后,顺序之后的也都满足条件,这时候就可以继续移动j了。
- 移动j的时候,由于j位置的元素变大了,k在上一轮的位置可以保持住
- 对于一般的3Sum,用的夹逼法:j和k,k反向移动:当k已经小了,之后的都是小的,所以移动j,否则移动k
- 对于本题:k已经小了那么所有之前的就都算上了,同时可以试新的j了,而新的j变大,所以只有k更小才可能(上轮的k保持位置)。所以j变大和k变小在一层发生,每次j/k都可以invalidate以前的一些cases
- triangle count:目标是要找到小于的第三边,如果k从右边界开始,当j变大的时候,k不能继续向左,只能reset到右边界。而k如果向右走,那么当第一个符合条件的时候,k只需继续,因为k左边的都已经必然满足了。
- 这题最好还是open to 可能性,然后根据题一个一个去验证。
- 优化:如果num[i]*3>=target,可以提前退出,类似Restore IP Addresses
# Given an array of n integers nums and a target, find the number of index triplets i, j, k with 0 <= i < j < k < n that satisfy the condition nums[i] + nums[j] + nums[k] < target.
# For example, given nums = [-2, 0, 1, 3], and target = 2.
# Return 2. Because there are two triplets which sums are less than 2:
# [-2, 0, 1]
# [-2, 0, 3]
# Follow up:
# Could you solve it in O(n2) runtime?
# Hide Company Tags Google
# Hide Tags Array Two Pointers
# Hide Similar Problems (M) 3Sum (M) 3Sum Closest
class Solution(object):
def threeSumSmaller(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: int
"""
n = len(nums)
count = 0
nums.sort()
for i in xrange(n-2):
if 3*nums[i]>=target:
return count
j,k = i+1, n-1
while j<k:
if nums[i]+nums[j]+nums[k]<target:
count+=k-j
j+=1
else:
k-=1
return count
sol = Solution()
assert sol.threeSumSmaller([-2, 0, 1, 3], 2)==2
assert sol.threeSumSmaller([3,1,0,-2], 4)==3