611. valid triangle number 有效三角形的个数
一、刷题内容
原题链接
https://leetcode-cn.com/problems/valid-triangle-number/
内容描述
给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。
示例 1:
输入: [2,2,3,4]
输出: 3
解释:
有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3
注意:
数组长度不超过1000。
数组里整数的范围为 [0, 1000]。
二、解题方法
1.方法一:排序 + 二分查找
对于正整数 a, b, ca,b,c,它们可以作为三角形的三条边,当且仅当:
a+b>c
a+c>b
b+c>a
均成立。如果我们将三条边进行升序排序,使它们满足 a≤b≤c,那么 a + c > b 和 b + c > a 使一定成立的,我们只需要保证 a + b > c。
注意到题目描述中 nums 包含的元素为非负整数,即除了正整数以外,nums 还会包含 0。但如果我们将 nums 进行升序排序,那么在枚举 a 和 b 时出现了 0,那么 nums[i] 一定为 0。此时,边 c 需要满足 c<nums[i]+nums[j]=nums[j],而下标在 [j + 1, n - 1][j+1,n−1] 范围内的元素一定都是大于等于 nums[j] 的,因此二分查找会失败。若二分查找失败,我们可以令 k = j,此时对应的范围长度 k - j = 0,我们也就保证了答案的正确性。
class Solution:
def triangleNumber(self, nums: List[int]) -> int:
n = len(nums)
nums.sort()
ans = 0
for i in range(n):
for j in range(i + 1, n):
left, right, k = j + 1, n - 1, j
while left <= right:
mid = (left + right) // 2
if nums[mid] < nums[i] + nums[j]:
k = mid
left = mid + 1
else:
right = mid - 1
ans += k - j
return ans
时间复杂度:O(n^2 log n),其中 n 是数组 nums 的长度。我们需要 O(n^2 log n) 的时间对数组 nums 进行排序,随后需要 O(n^2 log n)的时间使用二重循环枚举 a, b 的下标以及使用二分查找得到 c 的下标范围。
空间复杂度:O(logn),即为排序需要的栈空间。
2.方法二:排序 + 双指针
class Solution:
def triangleNumber(self, nums: List[int]) -> int:
n = len(nums)
nums.sort()
ans = 0
for i in range(n):
k = i
for j in range(i + 1, n):
while k + 1 < n and nums[k + 1] < nums[i] + nums[j]:
k += 1
ans += max(k - j, 0)
return ans
时间复杂度:O(n^2),其中 n 是数组 nums 的长度。我们需要 O(n logn) 的时间对数组 nums 进行排序,随后需要 O(n^2)的时间使用一重循环枚举 a 的下标以及使用双指针维护 b, c 的下标。
空间复杂度:O(logn),即为排序需要的栈空间。