兔系刷题leetcode系列之二 双指针

双指针

顾名思义,两个指针
做了很多题,一般有两种模式
一种i,j指针分别从头尾向中间
一种是i,j指针分别遍历两个部分

题目一 两数之和

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Fq1VDtbM-1585623546685)(D3F6878EF1AA48D4B39E15260DF95578)]

(为了讲解双指针,这题目改成返回[2,7]
当然原题目可以用哈希表快一点)

思路:

排序后,采用双指针,从而代码时间复杂度降到O(nlogn)
i指针从0开始
j指针从最后一位开始
若i指针上的数加上j指针上的数大于k,则j—,
否则i+

代码:

public static int[] twoSum(int[] nums, int target) {
	        Arrays.sort(nums); 
	        int i=0;
	        int j=nums.length-1;
	        while(i<j)
	        {
	        	if(nums[i]+nums[j]==target)
	        	{
	        		return new int[] {nums[i],nums[j]};
	        	}
	        	else if(nums[i]+nums[j]>target)
	        	{
	        		j--;
	        	}
	        	else if(nums[i]+nums[j]<target)
	        	{
	        		i++;
	        	}
	        }
	        return new int[] {};
	}

题目二 三数之和

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-b28zGUXX-1585623546686)(8CD814F70A794BD99FAC9F429A3C20A7)]

思路

在两数之和的基础上做题,采用双指针可将复杂度降到O(n2)
先排序
t指针到最后一个负数
i指针从t+1开始
j指针从最后一个指针开始

代码

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
         int t=0;
		 List<List<Integer>> a=new ArrayList<>();
		 if(nums.length==0)
			 return a;
		 Arrays.sort(nums);
		 
		 int q=nums[0];
		 while(t<nums.length&&nums[t]<0)
		 {
			 if(t!=0&&nums[t]==q)
			 {
				 t++;
				 continue;
			 }
			 int i=t+1;
			 int j=nums.length-1;
			
			 while(i<j)
			 {
				
				 if(nums[i]+nums[j]==-nums[t])
				 {
					 List<Integer> bIntegers=new ArrayList<>();
					 bIntegers.add(nums[t]);
					 bIntegers.add(nums[i]);
					 bIntegers.add(nums[j]);
					 a.add(bIntegers);
					 i++;
					 while(nums[i]==nums[i-1]) i++;
					 j--;
					 while(nums[j]==nums[j+1]) j--;
				 }
				 else if(nums[i]+nums[j]<-nums[t])
				 {
					 i++;
					 while(nums[i]==nums[i-1]) i++;
				 }
				 else {
					j--;
					while(nums[j]==nums[j+1]) j--;
				}	 
			 }
			 q=nums[t];
			 t++; 
		 }
		 return a;
    }
}

# 题目三 有序数组的平方

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZtNXSMEK-1585623546688)(1171EA4376B84B058C051D6E9A09DE3E)]

思路:

利用双指针i,j,分别从数组两头开始,i遍历负数部分,j遍历正数部分,利用双指针合并,合成所求数组。

代码:

class Solution {
    public int[] sortedSquares(int[] A) {
        int[] nums=new int[A.length];
	        int i=0;
	        int j=A.length-1;
	        int q=nums.length-1;
	        while(i<=j)
	        {
	        	int a=(int) Math.pow(A[i], 2);
	        	int b=(int) Math.pow(A[j], 2);
	        	if(a>=b)
	        	{
	        		nums[q]=a;
	        		i++;
	        	}
	        	else {
	        		nums[q]=b;
	        		j--;
	        	}
	        	q--;
	        }
	        return nums;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xA3avRPP-1585623546690)(D0A33C3A950345BBB152AC5EC89B1A80)]

题目四 接雨水

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tcq3sgyw-1585623546693)(58DD1BF4F2B54F378F362FCA252B8ED9)][外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dHs8nXM2-1585623546693)(46004E6682E845AC8796789C6133D90F)]

思路:

这题很棒!
我思考了很长时间
我认为理解这道题
首先要理解其实质
再理解如何通过双指针结合实质计算形式实现计算

实质:

什么决定了一点存储的雨量?
该点墙高-min(左边最高的墙,右边最高的墙)
如果是正数,那么代表该点存储的雨量

双指针:

我们设置两个指针i,j
分别从数组两边向中间进发
当我们可以确定一点的存储雨量,该指针向下一位置进发。

什么时候可以确定一点的存储雨量?

我们指针在遍历的时候,会存取maxleft,maxright
maxleft它针对i点是一定正确的,naxright是不一定正确的(因为没有遍历完,maxright只是针对j点的maxright)
再次回顾一点存储雨量的实质
假如针对i点 此时maxleft<maxright,说明
i点的雨量可以由maxleft决定
假如针对j点,此时maxright<maxleft,说明
j点的雨量可以由maxright决定

代码:

class Solution {
    public int trap(int[] height) {
        int sum=0;
		int maxleft=0;
		int maxright=0;
		int i=0;
		int j=height.length-1;
		while(i<=j)
		{
			if(maxleft<=maxright)
			{
				if(maxleft-height[i]>0)
				{
					sum=sum+maxleft-height[i];
					
				}
				if(height[i]>maxleft)
				{
					maxleft=height[i];
				}
				i++;
			}
			else {
				if(maxright-height[j]>0)
				{
					sum=sum+maxright-height[j];
					
				}
				if(height[j]>maxright)
				{
					maxright=height[j];
				}
				j--;
			}
			
		}
		return sum;
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZgeuN7v-1585623546697)(D2975AD108B64993907C97E3E5E2BD30)]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章