zoukankan      html  css  js  c++  java
  • 滑动窗口法与剑指offer:和为S的连续正数数列 与 和为S的两个数字

    和为S的连续正数数列

    输出描述:

    输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

    一开始看到这个题没有什么思路,实际上可以利用滑动窗口的思想来解决。

    left指向窗口左侧,right指向窗口右侧,一开始窗口不满足要求,因此要使窗口满足和为sum。当窗口和小于sum,要使他增大,因此移动窗口右侧:tmp+=++right;如果窗口和大于sum,要使他减小,则应该前移做窗口:tmp-=(left++);

    每当窗口满足要求,将当前结果输出,并再度破坏窗口平衡条件,tmp+=++right,让窗口遍历每一种情况。

    滑动窗口法非常适合这种数组形式的问题,大概流程为:

    1.使窗口满足条件

    2.输出结果

    3.破坏窗口平衡条件,使窗口右滑

    4.持续1~3直到窗口到最右侧

    class Solution {
    public:
        vector<vector<int> > FindContinuousSequence(int sum) {
            int left=1,right=2;
    		int tmp=3;
    		vector<vector<int>> ans;
    		while(left<right&&right<=(sum+1)/2)
    		{
    			while(tmp!=sum)
    			{
    				if(tmp==sum)
    					break;
    				else if(tmp<sum)
    					tmp+=++right;
    				else
    					tmp-=(left++);
    			}
    			if(left==right)
    				break;
    			vector<int> arr;
    			for(int i=left;i<=right;i++)
    				arr.push_back(i);
    			ans.push_back(arr);
    			tmp+=++right;
    		}
    		return ans;
        }
    };
    

      

     和为S的两个数字  

    输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。

    这个题也可以利用滑动窗口法,只是窗口中真正的有效信息是low与high,或者换句话说,真正的窗口不是[low,high]而是[0,low]与[high,end]组成的区间。

    当和过大,则应该缩小和,即将high--,而当和过小,则应扩大和,令low++,最终直到窗口大小等于整个数组大小,也就是[0,end]。

    class Solution {
    public:
        vector<int> FindNumbersWithSum(vector<int> array,int sum) {
    		if(array.empty())
    			return vector<int>();
    		int low=0,high=array.size()-1;
    		auto& num=array;
    		int g_min=INT_MAX;
    		int num1=0,num2=0;
    		while(low<high)
    		{
    			int tmp=num[low]+num[high];
    			if(tmp==sum)
    			{
    				if(num[low]*num[high]<g_min)
    				{
    					num1=num[low];
    					num2=num[high];
    					g_min=tmp;
    				}
    				high--;
    			}
    			else if(tmp<sum)
    				low++;
    			else
    				high--;
    		}
    		vector<int> ans;
    		if(INT_MAX!=g_min)
    		{
    			ans.push_back(num1);
    			ans.push_back(num2);
    		}
    		return ans;
        }
    };
    

      

    滑动窗口更像是另一种角度的遍历,传统的我们使用单个指针从0到end亦或是从end到0,这种遍历方式无法满足要求,而当我们该用滑动窗口,在窗口移动的过程中,我们其实也在遍历这个数组,当滑动窗口到头或滑动窗口扩大到整个数组的时候,我们遍历也就结束了。

    滑动窗口的方式相比这种单指针遍历,它在滑动的过程中保存住了信息,像单指针,在位置i与位置0其实没有区别,我们并不知道关于有关这个数组的信息,如果采用暴力搜索的方法,每次移动到位置i后,在位置i上用另一个指针遍历整个数组,得到了相关信息,但一旦我们将i移动到i+1,这部分信息就丢失了,相当于又要重新暴力的在搜索一遍这个数组。

    而滑动窗口的方式,我们每次移动,比如从i到i+1,实际上我们都保存住了i的信息,比如第一题,相比于暴力搜索,我们保留住了i的信息,在i+1位置,我们仍然知道上一个滑动窗口的和,从而不用在i+1处在重新暴力搜索,去找一个位置k,使k~i+1的连续和逼近S而去看看他是否满足要求,我们只要在上一个窗口的基础上去改变,现在发现连续和变大了,我们要使它变小,只要移动左侧指针就可以了,因为我们存有i位置IDE信息;又比如第二题,相比于暴力搜索,我们在i位置保存住了当前这两个数的和,从而当位置改变时我们不用再重新搜索另一个数,使与被搜索到的数的和去逼近S,因为我们已经保存住了上一个窗口的信息,我们知道,现在位置改变,和变小了,我只要在前一个窗口的基础上使这个和变大,也就是移动窗口左侧的指针就可以了。

  • 相关阅读:
    使用exe4j将java项目打成exe执行程序
    使用exe4j将java项目打成exe执行程序
    使用exe4j将java项目打成exe执行程序
    使用exe4j将java项目打成exe执行程序
    Java 数组 之 二维数组
    Java 数组 之 二维数组
    自定义右键菜单,禁用浏览器自带的右键菜单[右键菜单实现--Demo]
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
    xgqfrms™, xgqfrms® : xgqfrms's offical website of GitHub!
  • 原文地址:https://www.cnblogs.com/lxy-xf/p/11398191.html
Copyright © 2011-2022 走看看