兔系刷題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)]

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