290、三角形的最大周长

给定由一些正数(代表长度)组成的数组 nums ,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。如果不能形成任何面积不为零的三角形,返回 0

  

示例 1

输入:nums = [2,1,2]

输出:5

示例 2

输入:nums = [1,2,1]

输出:0

  

提示:

3 <= nums.length <= 104

1 <= nums[i] <= 106

来源:力扣(LeetCode)

链接:https://leetcode-cn.com/problems/largest-perimeter-triangle

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

package cn.fansunion.leecode.math;

import java.util.Arrays;

/**

 * 976. 三角形的最大周长 给定由一些正数(代表长度)组成的数组 nums ,返回 由其中三个长度组成的、面积不为零的三角形的最大周长 。 <br/>

 * 如果不能形成任何面积不为零的三角形,返回 0。 力扣

 *

 * @author wen.lei@brgroup.com

 *

 *         2022-2-26

 */

public class LargestPerimeterTriangle {

    /*示例 1:

     

    输入:nums = [2,1,2]

    输出:5

    示例 2:

     

    输入:nums = [1,2,1]

    输出:0

      

     

    提示:

    3 <= nums.length <= 104

    1 <= nums[i] <= 106*/

    /**

     * 排列组合,Cn3,符合“两边之和大于第三边”求和,维护最大的和

     * 思考:

     * 疑惑1:   “两边之和大于第三边” 可以推导出“两边之差小于第三边”吗?a+b>c,c-a<b,c-b<a,无法直接推出a-b<c。

     * (但是,b+c>a,也是肯定存在的,任意两边之和大于第三边。因此,三角形的2个规则,满足1个,另外1个自然就满足了,需要严格推理...)

     * 疑惑2:三角形3边关系,两边之和,两边之差,这2个条件都必须满足吗?还是说,满足了1个,另外1个自然就满足了。

     * 但是,官方的解法,只判断了2个较短的边 > 最长的边。道理可能是这么个道理,问题是:推理过程呢?

     * 这道题的本质不就变成了:数学中三角形的三边关系,2个基本规则,再加上本题可以知道的最长边,怎么简化判断条件吗?。

     * @param nums

     * @return

     */

     

    public int largestPerimeter(int[] nums) {

        // 自带的,从小到大

        Arrays.sort(nums);

        //3个数,都从大到小,满足3个条件的第1个就是最大周长

        for (int i = nums.length - 1; i >= 2; i--) {

            /* for (int j = nums.length-1; j >= 0; j--) {

                for (int k = nums.length-1; k >= 0; k--) {

                    final boolean threeDifNum = i != j && i != k && j != k;

                    final boolean sumLimit =

                        (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j]) && (nums[j] + nums[k] > nums[i]);

                    final boolean subLimit =

                        (nums[i] - nums[j] < nums[k]) && (nums[i] - nums[k] < nums[j]) && (nums[j] - nums[k] < nums[i]);

                    if (threeDifNum && sumLimit && subLimit) {

                        return nums[i] + nums[j] + nums[k];

                    }

                }

            }*/

            //两边之和,两边之差,据分析,可以互相推导

            //只用关心两边之和的情况下,排序后,相对顺序有了,c>=b>=a,满足条件的第1个就是了

            //这行表达式是对3个for循环内层2个for循环的简化,规律就是这么客观存在的

            //因此本题,本质是个数学中三角形的推理题

            final boolean sumLimit = (nums[i-1] + nums[i-2] > nums[i]);

            if(sumLimit) {

                return  nums[i-1] + nums[i-2] + nums[i];

            }

        }

        return 0;

    }

    public int largestPerimeterNotGood2(int[] nums) {

        // 自带的,从小到大

        Arrays.sort(nums);

        //3个数,都从大到小,满足3个条件的第1个就是最大周长

        for (int i = nums.length - 1; i >= 0; i--) {

            for (int j = nums.length-1; j >= 0; j--) {

                for (int k = nums.length-1; k >= 0; k--) {

                    final boolean threeDifNum = i != j && i != k && j != k;

                    final boolean sumLimit =

                        (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j]) && (nums[j] + nums[k] > nums[i]);

                    final boolean subLimit =

                        (nums[i] - nums[j] < nums[k]) && (nums[i] - nums[k] < nums[j]) && (nums[j] - nums[k] < nums[i]);

                    if (threeDifNum && sumLimit && subLimit) {

                        return nums[i] + nums[j] + nums[k];

                    }

                }

            }

        }

        return 0;

    }

    // 穷举,超时了,并且少了一个条件“两边之差小于第三边”

    public int largestPerimeterNotGood(int[] nums) {

        int max = 0;

        for (int i = 0; i < nums.length; i++) {

            for (int j = 0; j < nums.length; j++) {

                for (int k = 0; k < nums.length; k++) {

                    if (i != j && i != k && j != k && (nums[i] + nums[j] > nums[k]) && (nums[i] + nums[k] > nums[j])

                        && (nums[j] + nums[k] > nums[i])) {

                        max = Math.max(max, nums[i] + nums[j] + nums[k]);

                    }

                }

            }

        }

        return max;

    }

}

package test.leecode.math;

import org.junit.Assert;

import org.junit.Test;

import cn.fansunion.leecode.math.LargestPerimeterTriangle;

/**

 * @author wen.lei@brgroup.com

 *

 * 2022-2-25

 */

public class LargestPerimeterTriangleTest {

    @Test

    public void test() {

        LargestPerimeterTriangle test = new LargestPerimeterTriangle();

        int[] nums9=new int[] {2,3,4,7,11};

        Assert.assertEquals(9,test.largestPerimeter(nums9));

         

        int[] nums30=new int[] {1,2,3,4,5,6,7,8,9,10,11};

        Assert.assertEquals(30,test.largestPerimeter(nums30));

         

        int[] nums58=new int[] {1,2,3,4,5,16,17,8,9,20,21};

        Assert.assertEquals(58,test.largestPerimeter(nums58));

         

        int[] nums0=new int[] {1,3,5};

        Assert.assertEquals(0,test.largestPerimeter(nums0));

    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值