兔系刷刷leetcode系列之一 滑動窗口

滑動窗口的真實奧祕

一個窗口在數組上緩緩滑動
奧妙的是下一個窗口可以借鑑上一個窗口的值
字符串常用map存字母對應的位置

1. Maximum Sum Subarray of Size K (easy)

在這裏插入圖片描述

解決問題思路:

構建一個滑動窗口,在數組上緩緩滑動,下一個窗口的值是上一個窗口的值減去滑出的值,加上滑入的值。從而從暴力的O(N*K)變成O(N)

代碼:

public static int findMaxSumSubArray(int k, int[] arr)
	{
		int max=-1;
		if(arr.length>=k)
		{
			int i=0;
			int j=k-1;//滑動窗口邊界值
			int p=arr[i];
			int sum=0;
			for(int t=i;t<=j;t++)
			{
				sum=sum+arr[t];
			}
			max=sum;      //初窗口處理
			i++;
			j++;          //到下一個窗口
			while(j<arr.length)//直接當成一個窗口到下一個窗口更新過程就行
			{
				int q=arr[j];
				int l=arr[i];
				sum=sum-p+q;
				if(sum>max)
				{
					max=sum;
				}
				p=l;
				i++;
				j++;
			}
			
		}
		return max;
	}

2.Smallest Subarray with a given sum (easy)

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-mJ5sFAz4-1585408468007)(0E47BCDBCF8145FB9A4357D539695BA6)]

思路

在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述在這裏插入圖片描述

當sum(窗口)>=s時,存儲此時窗口長度,縮小窗口 i++;
當sun(窗口)<S時,擴大窗口長度,j++;

代碼

public static int findMinSubArray(int S, int[] arr) {
		  	int i=0;
		  	int j=0;
		  	int sum=0;
		  	while(sum<S&&j<arr.length)
		  	{
		  		sum=sum+arr[j];
		  		j++;
		  	} 
		  	j--;
		  	int k=j-i+1;
		  	if(sum<S)
		  	{
		  		return -1;
		  	}
		  	while(j<arr.length)
		  	{
		  		if(sum>=S)
		  		{
		  			if(j-i+1<k)
		  			{
		  				k=j-i+1;
		  			}
		  			sum=sum-arr[i];
		  			i++;
		  		}
		  		else {
		  			j++;
		  			if(j<arr.length)
		  			   sum=sum+arr[j];						
		  		}
		  	}
		  	return k;
		  }

3.Longest Substring with K Distinct Characters (medium)在這裏插入圖片描述

思路:

依然是滑動窗口
用map存取窗口內每個字母最後出現的位置
每次窗口變化時:

  1. i更新到min(每個字母最後出現的位置)+1
    並把去掉的字母從map中去除
  2. j更新到k個字母時的最遠位置

變化過程中,存取下滑動窗口最長值

public static int LongestSubstringKDistinct(String s,int k)
	{
		int len=-1;
		int i=0;
		int j=0;
		Map<Character, Integer> map=new HashMap<>();
		int t=0;
		while(map.size()<=k&&j<s.length())
		{
			char a=s.charAt(j);
			if(map.containsKey(a))
			{
				map.put(a,j);
			}
			else {
				if(map.size()==k)
				{
					break;
				}
				map.put(a,j);
			}
			j++;
		}
		j--;
		int maxlength=j-i+1;
		System.out.println("i:"+i);
		System.out.println("j:"+j);
		while(j<s.length())
		{
			i=minn(map);
			map.remove(s.charAt(i));
			i=i+1;
			System.out.println("i:"+i);
			while(map.size()<=k&&j<s.length())
			{
				j++;
				if(j>=s.length())
					break;
				char a=s.charAt(j);
				if(map.containsKey(a))
				{
					map.put(a,j);
				}
				else {
					if(map.size()==k)
					{
						j--;
						break;
					}
					map.put(a,j);
				}
			}
			if(j>=s.length())
				break;
			System.out.println("j:"+j);
			if(j-i+1>maxlength)
			{
				maxlength=j-i+1;
			}
		}
		return maxlength;
	}
	public static int minn(Map<Character, Integer> map)
	{
		int minn=Integer.MAX_VALUE;
		for(int value:map.values())
		{
			if(value<minn)
			{
				minn=value;
			}
		}
		return minn;
	}

4.水果成籃

在這裏插入圖片描述在這裏插入圖片描述在這裏插入圖片描述

思路:跟上面一題完全一樣的思路,只不過k=2

代碼:

class Solution {
    public static int minaddress(Map<Integer,Integer> map)
	{
		int min=Integer.MAX_VALUE;
		for(int value:map.values())
		{
			if(value<min)
			{
				min=value;
				
			}
		}
		// System.out.println("min:"+min);
		return min;
	}
	public  int totalFruit(int[] tree) {
	        int i=0;
	        int j=0;
	        Map<Integer, Integer> map=new HashMap<>();
	        while(j<tree.length)
	        {
	           int n=tree[j];
	           if(map.containsKey(n))
	           {
	        	   map.put(n, j);
	           }
	           else
	           {
	        	   if(map.size()==2)
	        	   {
	        		   j--;
	        		   break;
	        	   }
	        	   map.put(n, j);
	           }
	           j++; 
	        }
             if(j==tree.length)
	        {
	        	j--;
	        }
	        // System.out.println("i:"+i);
	        // System.out.println("j:"+j);
	        int maxnum=j-i+1;
	        // System.out.println("maxnum:"+maxnum);
	        while(j<tree.length&&i<j)
	        {
	        	i=minaddress(map);
	        	map.remove(tree[i]);
	        	i++;
	        	while(j<tree.length)
	        	{
	        	   j++;
	        	   if(j==tree.length) {
	        		   j--;
	        		   break;
	        	   }
	        	   int n=tree[j];
	        	   if(map.containsKey(n))
	   	           {
	   	        	   map.put(n, j);
	   	           }
	   	           else
	   	           {
	   	        	   if(map.size()==2)
	   	        	   {
	   	        		   j--;
	   	        		   break;
	   	        	   }
	   	        	   map.put(n, j);
	   	           }
	        	}
	        	if(j-i+1>maxnum)
	        	{
	        		maxnum=j-i+1;
	        	}
	        	// System.out.println("i:"+i);
	  	        // System.out.println("j:"+j);
	  	        // System.out.println("maxnum:"+maxnum);
	        }
	        return maxnum;
	        
	    }
}


[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-iVFnq1NI-1585408468040)(96B935C98DD34560A0036A31A36086B3)]

無重複字符的最長子串

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-l0cZvBhk-1585408468041)(C727A676A69340DD85911A453EF70BD6)][外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ZxiMQPBm-1585408468043)(811C0A2A42714E39AF8C6E2401703A54)]

思路:

滑動窗口,用map保存字符串中每個字母的最後位置。
窗口更新時,j往後移動一位,假如s(j)在前面已經有了,i更新到這個字母在之前的最後的位置+1。
窗口變換過程中,保存窗口最大長度。

代碼:

class Solution {
    public int lengthOfLongestSubstring(String s) {
        	
		int i=0;
		int j=0;
		Map<Character, Integer> map=new HashMap<>();
		while(j<s.length()&&!map.containsKey(s.charAt(j)))
		{
			map.put(s.charAt(j), j);
			j++;
		}
		j--;
//		System.out.println("i:"+i);
//    	System.out.println("j:"+j);
		int maxlength=j-i+1;
	    while(j<s.length())
	    {
	    	j++;
	    	if(j==s.length())
	    		break;
	    	char c=s.charAt(j);
//	    	System.out.println("c:"+c);
//	    	System.out.println("map.get(c):"+map.get(c));
	    	if(map.containsKey(c))
	    	{
	    		if(map.get(c)>=i)
	    		{
	    			i=map.get(c)+1;
	    		}
	    	}
	    	map.put(c,j);
//	    	System.out.println("i:"+i);
//	    	System.out.println("j:"+j);
	    	if(j-i+1>maxlength)
	    	{
	    		maxlength=j-i+1;
	    	}
	    }
	    return maxlength;
    }
}

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-8aDUjwdg-1585408468046)(8EF1AF55C07D4F4DB79E7A9E8DCDFE65)]

5.最小覆蓋子串

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-I4g2atpX-1585408468048)(A25FBD7F6BAC4733B251F101FE40EE41)]


T=“AAABBBCCC”
代表着s中要有A,B,C
(我不管,我就把這題當成這樣做了,不想改了。)

思路:

滑動窗口

初始窗口:找到包含全部目標字母的第一個字符串,j在移動過程中若有跟邊界字母(s(i))相同的,則i更新到下一個字母

窗口更新:
i更新到下一個字母
j找到i移動去掉的原邊界字母,當然j在移動過程中若有跟邊界字母(s(i))相同的,則i更新到下一個字母。

代碼:

class Solution {
   public String minWindow(String s, String t) {
		 int i=0;
		 int j=0;
		 Map<Character,Integer> map=new HashMap<>();
		 Set<Character> diCharacters=new HashSet<>();
		 for(int l=0;l<t.length();l++)
		 {
			diCharacters.add(t.charAt(l));
		 }
		 while(i<s.length()&&!diCharacters.contains(s.charAt(i)))
		 {
			 i++;
		 }
		 char d=s.charAt(i);
		 map.put(d,i);
		 while(map.size()!=diCharacters.size())
		 {
			 j++;
			 if(j==s.length())
				 return "";
			 char h=s.charAt(j);
			 if(h==d)
			 {
				 map.put(h,j);
				 i=minaddress(map);
				 d=s.charAt(i);
			 }
			 else if(diCharacters.contains(h))
			 {
				 map.put(h, j);
			 }
		 }
		//  System.out.println("i:"+i);
		//  System.out.println("j:"+j);
		 int mini=i;
		 int minj=j;
		 while(j<s.length()&&i<j)
		 {
			 map.remove(s.charAt(i));
			 i=minaddress(map);
			 d=s.charAt(i);
			 while(map.size()!=diCharacters.size())
			 {
				 j++;
				 if(j==s.length())
					 break;
				 char h=s.charAt(j);
				 if(h==d)
				 {
					 map.put(h,j);
					 i=minaddress(map);
					 d=s.charAt(i);
				 }
				 else if(diCharacters.contains(h))
				 {
					 map.put(h, j);
				 }
			 }
			 if(j==s.length())
				 break;
			//  System.out.println("i:"+i);
			//  System.out.println("j:"+j);
			 if(j-i+1<minj-mini+1)
			 {
				 minj=j;
				 mini=i;
			 }
			 
		 }
		 
		 return s.substring(mini,minj+1);
	}
	public static int minaddress(Map<Character, Integer> map)
	{
		int min=Integer.MAX_VALUE;
		for(int value:map.values())
		{
			if(min>value)
			{
				min=value;
			}
		}
		return min;
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章