力扣每日一题2021-08-04有效三角形的个数

力扣每日一题21.08.04有效三角形的个数


611.有效三角形的个数

题目描述

给定一个包含非负整数的数组,你的任务是统计其中可以组成三角形三条边的三元组个数。


示例1

输入:

[2, 2, 3, 4]

输出:

3

解释:

有效的组合是:
2, 3, 4(使用第一个2
2, 3, 4(使用第二个2
2, 2, 3


注意:

1.数组长度不超过1000
2.数组里整数的范围为[0, 1000]。


思路:

排序+遍历(肯定超时)、排序+二分查找、排序+双指针


排序+遍历(没有时间限制的情况下可以用)

思路:对于三个正整数a, b, c而言,如果要作为三角形的三条边,必须满足两边之和大于第三边的规则,因此有a+b>c、a+c>b、b+c>a均成立。
如果对三条边进行升序排序,使得满足a<=b<=c,则a+c>b、b+c>a必定成立,只需要保证a+b>c即可满足条件
所以,可以对给定的nums数组进行排序,枚举出边a和b。假定a和b对应的nums数组的元素index分别是i和j,则i<j,因为依据题意同一个位置的值不能取两次,而第三条边c则需要满足c<a+b,可以在[j+1, len(nums)-1]的范围内从右往左遍历,找出最大的满足边c<a+b的nums对应元素index,假定这个index为k,则在[j+1, k]范围内的index对应的nums元素都可以作为边c,将该范围长度k-j累加到结果中。当枚举完成后返回累加的结果即可。另外考虑到不能取到index相同的值,作为三条边,所以i应该在[0, len(nums)-3],j应该在[1, len(nums)-2],k应该在[2, len(nums)-1]。还有一个需要考虑的是nums数组为非负整数,所以如果遍历到0边,可以将j和k都设置为0,则k-j同样为0,不会对结果产生影响。

python实现
class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        nums = sorted(nums)
        n = len(nums)
        sum = 0
        for i in range(n-2):
            for j in range(i+1, n-1):
                for k in range(n-1, j, -1):
                    if nums[i] != 0 and nums[j] != 0 and nums[k] != 0 and nums[i] + nums[j] > nums[k]:
                        sum += k-j
                    else:
                        sum += 0
        return sum

排序+二分查找

这种思路是对上面的思路的一种优化,整体思想与上面的思路一样,只不过将三层遍历改为两层遍历,第三层遍历查找边c改为在[j+1, len(nums)-1]范围内用二分查找找到最大的边c的下标k。同样需要对0边进行操作。

python实现

排序+二重循环+二分查找

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
        # 排序+二层遍历+二分查找
        nums = sorted(nums)
        n = len(nums)
        sum = 0
        for i in range(n-2):
            for j in range(i+1, n-1):
                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
                sum += max(k - j, 0)
        return sum

排序+双指针

该思路是对二分查找的优化,整体思路与排序+二分查找思路一样,但是将二分查找改为双指针遍历。
假定a=nums[i],b=nums[j],最大满足nums[k]<nums[i]+nums[j]的下标k。如果固定i,随着j的递增,不等式右侧也是递增的,所以k也是递增的。
则可以将j和k看做两个同向移动的指针。将排序+二分查找进行优化:

  • 一重循环枚举i。固定i,使用双指针维护j和k,初始值均为i;
  • 每次将j向右移动一个位置,并尝试不断向右移动k,使得k是最大满足nums[k]<nums[i] + nums[j]的下标。将max(k-j, 0)累加到结果。
python实现

排序+双指针

class Solution:
    def triangleNumber(self, nums: List[int]) -> int:
    	# 排序+双指针
        nums = sorted(nums)
        n = len(nums)
        sum = 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
                sum += max(k - j, 0)
        return sum
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值