题目链接
1.盛最多水的容器:11. 盛最多水的容器 - 力扣(LeetCode)
2.三数之和: 15. 三数之和 - 力扣(LeetCode)
题目一:盛最多水的容器
题目描述
给定一个长度为
n
的整数数组height
。有n
条垂线,第i
条线的两个端点是(i, 0)
和(i, height[i])
。找出其中的两条线,使得它们与
x
轴共同构成的容器可以容纳最多的水。返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例1
输入:[1,8,6,2,5,4,8,3,7] 输出:49 解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例2
输入:height = [1,1] 输出:1
解题思路
我们最容易想到的就是暴力枚举每一种情况,然后计算出面积最大的结果。但是暴力很容易就超时了,所以我们考虑换一种思路。
这道题标签既然是双指针,而且要计算面积,那么就定左右指针,分别指向左右两端,这样就把要计算的容器给框出来了。
我们先搞清楚一个前提:容器的高度是由较高的边确定,还是较低的边确定呢?我们就拿示例1来讲,如图
自然是以较低的边来确定高度,这样才能把水装住。在上图这种情况下,我们发现此时底边是最长的。那还有没有必要拿第一个柱子和其他柱子计算容量呢?假使随机选择一根
这个时候,我们发现:
高度没变,底边倒是变短了,那体积自然就缩小了。
所以我们现在可以回答这个问题了:那还有没有必要拿第一个柱子和其他柱子计算容量呢?
答案是:没有必要了!
因为我们发现,拿较低的那根柱子和其他柱子去组成容器的话,高度是以较低的那根柱子决定的,即便我们找出的柱子高度很高,那最终还是要以这根低的为准,同时底边缩小了;如果找到了更低的柱子和这根柱子组合,那高度岂不是更低了吗,体积就更小了。所以我们大胆地提出一种思路:
①先定义左右指针,分别指向数组两端;
②然后我们计算得到一个值。
③之后将左右两根柱子高度做比较,如果左边更低的话, 那就没必要将左边的柱子和其他柱子组合了,那么就移动左边柱子;否则移动右边柱子;
④循环第③步,每次都计算出一个体积值,取最大值即可。
简单来说,其实就是排除了一些更小的数据,只需要考虑较大的那部分。
其实我也是参考的评论区大神题解,这里有动图:
11. 盛最多水的容器 - 力扣(LeetCode)
代码实现
class Solution {public int maxArea(int[] nums) {//双指针int left=0;int right=nums.length-1;int area=0;while(left<right){int temp=(right-left)*Math.min(nums[left],nums[right]);area=Math.max(area,temp);if(nums[left]>nums[right])right--;else left++;} return area;}
}
题目二:三数之和
题目描述
给你一个整数数组
nums
,判断是否存在三元组[nums[i], nums[j], nums[k]]
满足i != j
、i != k
且j != k
,同时还满足nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为0
且不重复的三元组。注意:答案中不可以包含重复的三元组。
示例1
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]]
解释:
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。
不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。
注意,输出的顺序和三元组的顺序并不重要。
示例2
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例3
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
解题思路
这道题官方给的标签依然是双指针。
①先对数组进行升序排序。
②然后固定一个数,下标为i,之后定义左指针为i+1,右指针指向最后一个数。如果固定的这个数与它前一个数相等,说明之前已经统计过了,跳过。
③在“左指针小于右指针”的前提下,先判断固定的这个数是否大于0。
④如果它都大于0了,那后面的肯定更是大于0,加起来不可能为0的,此时直接跳出循环就好。
⑤如果结果小于0,说明需要找到更大的数,那么就移动左指针;如果结果大于0,说明需要缩小一点,就移动右指针。
⑥搜集到一组结果之后,要对剩余的两个数做“去重”操作:如果左指针指向的数与它后一个数相等,移动左指针;如果右指针指向的数与它前面的数相等,移动右指针。因为相同的数已经计算过了,再计算就重复了。
代码实现
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;class Main {public static void main(String[] args) {List<List<Integer>> lists = threeSum(new int[]{-1, 0, 1, 2, -1, -4});System.out.println(lists);}public static List<List<Integer>> threeSum(int[] nums) {//排序Arrays.sort(nums);//遍历每一个数int length = nums.length;List<List<Integer>> resultList = new ArrayList<>();for (int i = 0; i < length; i++) {//收取结果后,去重if (i > 0 && nums[i] == nums[i - 1])continue;//最小的数都大于0了,后面的就不用看了if (nums[i] > 0)break;//找其余两个数int left = i + 1;int right = length - 1;while (left < right) {//看是否等于0if (nums[i] + nums[left] + nums[right] > 0)right--;else if (nums[i] + nums[left] + nums[right] < 0)left++;else {resultList.add(Arrays.asList(nums[i], nums[left], nums[right]));//对中间数去重while (left < right && nums[left] == nums[left + 1])left++;while (left < right && nums[right] == nums[right - 1])right--;left++;right--;}}}return resultList;}
}