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;
|