双指针
双指针
Leetcode Hot100第二个小专题,前两道为移动零以及盛水最多的容器,暂时未记笔记.
移动零
力扣题目连接:移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
解题思路:这道题可以用一个额外的数组来存储非零元素,然后补齐零,重新赋值给nums,缺点就是空间复杂度较低;使用双指针,效果更好。java数组没有swap函数得自己定义,有点小麻烦。
class Solution {
public void moveZeroes(int[] nums) {
int n = nums.length;
int left = 0;
int right = 0;
while(right<n){
if(nums[right]!=0){
swap(nums,left,right);
left++;
}
right++;
}
}
public void swap(int[] nums ,int left, int right){
int temp = nums[left];
nums[left] = nums[right];
nums[right]=temp;
}
}
盛最多水的容器
力扣题目连接:盛最多水的容器
给定一个长度为 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
解题思路:使用双指针从两边开始往中间遍历,柱子肯定都要遍历一遍的,万一中间两个是一亿的高度呢对吧,乾坤未定你我皆是黑马了,每次都要计算能接水的区域大小,然后跟result做一个比较,取最大值。计算时应该遵循水桶效应,肯定是低的那根柱子决定接水区域的高度。同时每次也应该是比较低的柱子先向后遍历(如果高的先向后遍历,即使下一个再高,也是由前一个矮的决定高度,宽度还变小了,所以区域只会越来越小)
class Solution {
public int maxArea(int[] height) {
int left = 0;
int right = height.length-1;
int area = 0;
int result = 0;
while(left<right){
area = Math.min(height[right],height[left]) *(right-left);
result = Math.max(area,result);
if(height[left]<height[right]){
left++;
}
else{
right--;
}
}
return result;
}
}
三数之和
力扣题目连接:三数之和
给你一个整数数组 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 。
输入:nums = [0,0,0]
输出:[[0,0,0]]
解释:唯一可能的三元组和为 0 。
代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end()); //排序之后
set<vector<int>> result; //使用set方便去重
for(int i=0;i<nums.size()-2;i++){
if(nums[i]>0){ //因为nums[i]值大于0,由于排序,其后面的两个值一定大于等于nums [i],三者相加一定不为0;那么nums[i]后面的值也同理,直接结束循环即可
break;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int l=i+1;
int r=nums.size()-1;//定义双指针
while(l<r){
if(nums[i]+nums[l]+nums[r]<0){
l++;
}
else if(nums[i]+nums[l]+nums[r]>0){
r--;
}
else{
result.insert({nums[i],nums[l],nums[r]});
l++;
r--;
}
}
}
vector<vector<int>> ans(result.begin(),result.end());
return ans;
}
};
接雨水 ⭐⭐⭐⭐⭐困难题目 着重理解
力扣题目连接:接雨水
给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。
示例 1:
[](https://imgse.com/i/pEvcCxx)
输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。
示例 2:
输入:height = [4,2,0,3,2,5]
输出:9
代码:
class Solution {
public:
int trap(vector<int>& height) {
int result=0;
int left=0;
int right=height.size()-1;
int leftMax,rightMax=0;
while(left<right){
leftMax=max(height[left],leftMax);//因为leftMax是由height[left]更新过来的,所以在当前这个循环,leftMax一定>=height[left]
rightMax=max(height[right],rightMax);//同理,rightMax一定>=height[right];
if(height[left]<height[right]){ //那么这个时候height[left]一定<=leftMax和rightMax,所以更新left
result+=min(leftMax,rightMax)-height[left];
left++;
}
else{ //同理,此时更新right
result+=min(leftMax,rightMax)-height[right];
right--;
}
}
return result;
}
};