兔系刷刷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;
	}
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值