文章目录
- 前言
- 一、有效三角形个数
- 1, 题目
- 2, 思路分析
- 1, 从左往右 or 从右往左?
- 3, 代码展示
前言
各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你:
📕 JavaSE基础: 基础语法, 类和对象, 封装继承多态, 接口, 综合小练习图书管理系统等
📗 Java数据结构: 顺序表, 链表, 堆, 二叉树, 二叉搜索树, 哈希表等
📘 JavaEE初阶: 多线程, 网络编程, TCP/IP协议, HTTP协议, Tomcat, Servlet, Linux, JVM等(正在持续更新)
一、有效三角形个数
1, 题目
OJ链接
其实这题本质也是查找, 而查找的本质是排除 ! ! 查找的本质是排除 ! ! 查找的本质是排除 ! !
2, 思路分析
最简单的暴力枚举 : 三层 for 循环, 从先固定两个数, 再依次遍历第三个数, 判断这三个数是否能组成三角形, 时间复杂度为O(N³), 会超出时间限制
既然暴力枚举不行, 那尝试就使用双指针, 但我们要找三个数, 只能先固定一个数, 在剩余区间上, 使用双指针(left和right) 找到另外两个数, 尽可能让双指针找全所有正确组合
根据实际情况分析选择对撞双指针还是快慢双指针, 本题要求在数组中"查找", 那么使用对撞双指针能很大程度上提高效率
而且刚才标注了一句话 : 查找的本质是排除, 查找的本质是排除, 查找的本质是排除 ! ! !
如果每次判断, 都能尽可能多的排除数据, 就能尽可能地提高效率
本题有两种基本思路 :
-
1, 定义 i 指针, 先固定较小的数, 剩余区间使用双指针, i 从左往右遍历
-
2, 定义 i 指针, 先固定较大的数, 剩余区间使用双指针, i 从右往左遍历
1, 从左往右 or 从右往左?
在正式开始之前, 需要对原数组进行排序, 这是常见的作法, 因为一般数组有序时, 成单调性, 能够更高效的进行"排除"
定义变量 count 表示找到有效三角形的个数
count = right
(6下标)
- left(4下标)
这行代码表示 : left 不需要再向右遍历了, 已经找到了3, 8, 10
和3, 9, 10
这两个有效三角形了, right - left 的值就是 i 为 0 下标, right 为 6 下标时有效三角形的个数, 下面的示例同理
上述两种遍历的方式, 其实应该选择让 i 先固定最大值, 从右往左遍历, 因为第一种方式, 没有让 right 向左遍历, 如果让 right 向左遍历, 就不能使用双指针这种高效的方式了
- 让 i 固定最小值, 从左往右遍历, 会导致 left 在向右遍历时, 虽然也能实现排除(省略不必要的遍历), 但由于 right 无法向左遍历, 会跨过一部分正确的组合, 要想找全遗漏的正确的组合, 就得让 right 向左遍历, 而 left 也必须回到 i + 1 的位置重新向右遍历(因为 left 已经向右移动很多了), 这样其实相当于暴力枚举
- 让 i 固定最大值, 从右往左遍历, 既能让 left 向右遍历, "排除"也只是派出了left向右遍历的情况, 同时也能让 right 向左遍历, 所以能找全所有的正确组合, 而且排除(省略不必要的遍历)效率很高
3, 代码展示
public int maxArea(int[] height) {public int triangleNumber(int[] nums) {// 1, 从左往右先固定一个数// 2, 剩下两个数在剩余区间内, 对撞指针Arrays.sort(nums);int i = 0;int count = 0;while(i < nums.length - 2) {int left = i + 1;int right = nums.length - 1;while(left < right) {if(nums[i] + nums[left] > nums[right]){count += right - left; // 利用单调性快速寻找right--;}else{left++;}}i++;}return count;}