每日算法篇(一)之有效三角形的个数

336 阅读2分钟

这是我参与8月更文挑战的第4天,活动详情查看:8月更文挑战

作为一个算法菜鸟来说,每日一题是我督促自己最后的倔强!!!做多了其实对于我自己来说,更多的是思维转换,以前首当其冲的是暴力+循环,能跑出来结果并通过就O了(虽然现在也是)。每次打开算法题,基本步骤就是 思考→ 循环暴力→超时(或用例不通过)重复数次→通过(击败1%),属实是难受啊....

题目

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

示例 1:

输入: [2,2,3,4]
输出: 3
解释:
有效的组合是: 
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

拿到今天的题目,感觉描述很少嘛~不过没关系,数学底子还是有的。

审题

  • 首当其冲的就是三角形的三条边嘛,a+b>c的公式还是记得的
  • 非负整数,圈住重点(三次测试用例失败均在此),需要防止有0的出现
  • 对于循环狗来说,a+b>c的前提是数组需要升序

代码实现

好了,蠢逼的做法,大家看看就行~

  1. 先来一波校验数组
  2. 用Arrays.sort对数组进行一次升序
  3. 第一层循环获取当前值,并对0判断
  4. 第二层循环对第一层的指针动态后移,,并对0判空
  5. 第三层循环 再对第二层指针动态后移,并对0判空
  6. 并在第三层循环中做出a+b>c的判断
    public int triangleNumber(int[] nums) {
        if(nums.length<3){
            return 0;
        }
        Arrays.sort(nums);
        int max =0;
        for (int i = 0; i <nums.length; i++) {
            int a = nums[i];
            if(a == 0){
                continue;
            }
            for (int j = i+1; j <nums.length ; j++) {
                int b = nums[j];
                if(b == 0){
                    continue;
                }
                for (int k = j+1; k < nums.length; k++) {
                    int c = nums[k];
                    if(c == 0){
                    continue;
                    }
                    if (a+b>c){
                        max++;
                    }
                }
            }
        }
        return max;
    }

1628064684(1).jpg

官方题解

由于a+b>c的原理,转换到数组则是 nums[k] < nums[i] + nums[j],在固定下标 i 的前提下,下标K随着下标j的递增而递增。这两个是同向递增移动的指针。我们每一次将 j 向右移动一个位置,即 j←j+1,并尝试不断向右移动 k,使得 k 是最大的满足 nums[k] < nums[i] + nums[j] 的下标。我们将 max(k - j, 0) 累加入答案。

class Solution {
    public int triangleNumber(int[] nums) {
        int n = nums.length;
        Arrays.sort(nums);
        int ans = 0;
        for (int i = 0; i < n; ++i) {
            int k = i;
            for (int j = i + 1; j < n; ++j) {
                while (k + 1 < n && nums[k + 1] < nums[i] + nums[j]) {
                    ++k;
                }
                ans += Math.max(k - j, 0);
            }
        }
        return ans;
    }
}

总结

对于本次的题目,其实一开始就想到了双指针的方式,但是没能拓宽思路,只知道埋头苦干,没能拓宽了我的对双指针的视野。