使用以下算法:
给定n个整数nums和target的数组,找到数字 索引三元组i,j,k,其中0 <= i <1。 j&lt; k&lt;满足的 条件nums [i] + nums [j] + nums [k]&lt;目标
例如,给定nums = [-2,0,1,3]和target = 2.
返回2.因为有两个三元组,其总和小于2:
def three_sum_smaller(nums, target)
nums.sort!
i = 0
triplet_count = 0
while i < nums.length
j = i + 1
while j < nums.length
pair_sum = nums[i] + nums[j]
val = target - pair_sum
k = binary_search(nums, val) #if val in it, we want all indices between j and k. else all indices j and k including k.
(nums[k] == val) ? triplet_count += (j + 1...k).size : triplet_count += (j + 1..k).size #ensures k > j.
j += 1
end
i += 1
end
triplet_count
end
def binary_search(arr, val)
b_search(arr, val, 0, arr.length - 1)
end
def b_search(arr, val, low, high)
while low < high
mid = (low + high) / 2
if arr[mid] > val #left half
high = mid - 1
elsif arr[mid] < val
low = mid + 1
else
#go left until it's no longer k and return this.
until arr[mid] != val
mid -= 1
end
return mid
end
end
low
end
对于以下测试用例,我的代码为1:
arr = [-3,4,-4,1,-1,-2,-1,-1,-5]
target = -3
Correct output: 48
My output: 59
该方法的工作原理如下。对于每个可能的对,执行二进制搜索,查找使得对的总和==目标的值。如果此值不存在,则返回小于它的索引。如果是,则返回该值的第一个匹配项。然后,如果找到该值,则仅将j和k之间的指数(excl k)作为三元组完成。如果未找到该值,则将索引包含j作为三元组完成。
这适用于200个左右的测试用例,之后失败了。我不确定出了什么问题......
答案 0 :(得分:1)
愚蠢的问题:鉴于200个测试用例通过,但有一个失败,您确定给出的测试输出是否正确?
从另一个角度来看:我对这个算法的解释(如果我误解了,那就道歉了!)就是你要找到产生总和少的三元组的总数比目标。三元组不能重复使用相同的数字,否则可以按任何顺序重复。
碰巧,Ruby使用validator
生成长度为 n 的组合非常容易(https://ruby-doc.org/core-2.2.0/Array.html#method-i-combination)
使用它,我们可以生成所有独特的三元组。然后,对每一个进行求和是微不足道的,看它是否符合标准。
因此,沿着这些方向的替代解决方案可能如下所示:
validator(blacklist: list=['heck', 'muffins']) -> ???:
根据您提供的输入,这支持您对48的回答:
combination
答案 1 :(得分:1)
问题在于在将范围添加到triplet_count
之前进行等式检查。您需要检查>=
而不是==
,如下所示:
def three_sum_smaller(nums, target)
nums.sort!
i = 0
triplet_count = 0
while i < nums.length
j = i + 1
while j < nums.length
pair_sum = nums[i] + nums[j]
val = target - pair_sum
k = binary_search(nums, val)
(nums[k] >= val) ? triplet_count += ((j + 1)...k).size : triplet_count += ((j + 1)..k).size
j += 1
end
i += 1
end
triplet_count
end
当您检查相等性时,您错过了位置k
上的数字可能大于val
的事实,因此它不代表有效的三元组。
无论如何,如果我们使用以下想法,解决方案可以降低到O(N ^ 2):
我们可以修复索引(idx
),然后使用两个指针(start
和finish
)迭代搜索从idx + 1
到nums.length - 1
的子数组找到有效范围以完成三元组。代码如下所示:
def three_sum_smaller_without_search(nums, target)
nums.sort!
triplet_count = 0
nums.each_with_index do |val, idx|
start = idx + 1
finish = nums.length - 1
while start < finish
if val + nums[start] + nums[finish] >= target
finish -= 1
elsif val + nums[start] + nums[finish] < target
triplet_count += finish - start
start += 1
end
end
end
triplet_count
end