滑动窗口算法(C语言描述)

第一种类型:不固定长窗口

问题1:***

C代码1:

#include<stdio.h>
#include<string.h>
#define N 5

int min_len(int len1,int len2)
{
	return (len1 < len2 ? len1:len2);
}

int main()
{
	int target = 0;
    int num[N];
	scanf("%d",&target);
	for(int i = 0;i < N;i++)
	{
		scanf("%d",&num[i]);
	}
	
	
	//滑动窗口算法
	int left = 0;
	int right = 0;
	int sum = 0;
	int len = N+1;
	while(right < N)
	{
		sum += num[right];
		while(sum >= target)
		{
			sum -= num[left];
			if(sum < target)
			{
				len = min_len(len,right-left+1);
			}
            left++;
		}
		right++;
	}
	if(len == N+1)
	{
		printf("No such subarray exists!");
	}
	else
	{
		printf("%d",len);
	}
	
	return 0;
}

 问题2:*****

C代码2: 

#include<stdio.h>
#include<string.h>
#define N 80

//向窗口右边添加一个字符,拓宽窗口
void Add_char(char ch,char *window)
{
	int right = strlen(window);
	window[right] = ch;
}
//检查窗口字符串是否满足包含字符串t所有字符且数量不少于t
int Is_ok(char *t,char *window)
{
	int needs[128]={0};
	int windows[128]={0};
	int n=0;
	int w=0;
    int len1 = strlen(window);
    int len2 = strlen(t);
	for(int i=0;i<len1;i++)
	{
		w = (int)window[i];
		windows[w]++;
	}
	for(int j=0;j<len2;j++)
	{
		n = (int)t[j];
		needs[n]++;
	}
	for(int k = 0;k < 128;k++)
	{
		if(needs[k] != 0 && windows[k] < needs[k])
		{
			return 0;//不满足条件
		}
	}
	return 1;//满足条件
}

/*判断当前满足条件的窗口字符串和满足条件的上一次结果字符串比较谁更短,并更新结果。
注意这里不要单纯的把指针result指向新结果(也就是窗口),因为窗口会随着循环而改变,
这样无法保留做中的正确结果,应该把结果字符串赋值给指针result指向的空间*/
void minlen(char *result,char *window)
{
	int result_len = strlen(result);
	int window_len = strlen(window);
	if(result_len > window_len)
    {
        for(int i = 0;i <= window_len;i++)
        {
            result[i] = window[i];
        }
    }
}

//移除窗口左边第1个字符
void remove_char(char *window)
{
    int len = strlen(window);
	for(int i= 0;i < len;i++)
	{
		window[i] = window[i+1];
	}
}

int main()
{
	//定义所需字符数组
	char s[N];//存储字符串s
	char t[N];//存储字符串t
	char window[N]={'\0'};//窗口内的字符串
	char *result = s;//存储找到的满足条件的最短字符串,这里初始化时将其指向字符串s
	
	//输入字符串s和t
	scanf("%s",s);
	scanf("%s",t);
	
	//定义滑动窗口所需变量
	int left = 0;//窗口左边界指针
	int right = 0;//窗口右边界指针
	int end = strlen(s);//字符串s的长度,窗口滑动的终止点
	//开始滑动窗口寻找满足条件的最短字符串
    int flag = 0;
	while(right < end)
	{
		Add_char(s[right],window);//拓宽窗口右边界
		while(Is_ok(t,window)&&left < end)//窗口满足条件,已包含字符串t所有字符且数量也不少
		{
            flag = 1;
			minlen(result,window);//更新最短满足条件子串答案
            remove_char(window);//移除窗口左边第1个字符
			left++;//窗口左边界边界向前滑动
		}
		right++;
	}
    if(flag)
    {
        printf("%s\n",result);
    }
    else
    {
        printf("No such string!\n");
    }
	return 0;
}

问题3:

C代码3:

(代码版本1)和上面一个题目差不多,只不过在这里更新答案要加点条件。

#include<stdio.h>
#include<string.h>

//向窗口右边添加一个字符,拓宽窗口
void add_char(int right,char *s,char *window)
{
	int len = strlen(window);
	window[len] = s[right];
}

//检查窗口字符串是否满足包含字符串t所有字符且数量不少于t
int Is_ok(char *window,char *p)
{
	int len_w = strlen(window);
	int len_p = strlen(p);

	int windows[128]={0};
	int ps[128]={0};
	
	int t=0;
	for(int i = 0;i<len_w;i++)
	{
		t = (int)window[i];
		windows[t]++;
	}
	for(int j = 0;j<len_p;j++)
	{
		t = (int)p[j];
		ps[t]++;
	}
	for(int k = 0;k<128;k++)
	{
		if(ps[k] != 0&& ps[k] > windows[k])
		{
			return 0;
		}
	}
	return 1;

}

//移除窗口左边第1个字符
void remove_char(char *window)
{
	int len_w = strlen(window);
	for(int i=0;i<len_w;i++)
	{
		window[i] = window[i+1];
	}
	
}
int main()
{
	//定义字符数组
	char s[20101]={'\0'};
	char p[20101]={'\0'};
	char win[20101]={'\0'};
	//输入字符串s和p
	scanf("%s",s);
	scanf("%s",p);
	//滑动窗口求解答案
	int left = 0;
    int right = 0;
    char *window = win;
    int end = strlen(s);
    
	int flag = 0;//检查s中满足条件的子字符串是否大于0
	int index_arr[1000]={0};
	int x = 0;
    while(right < end)
    {
    	add_char(right,s,window);
    	while(Is_ok(window,p)&&left < end)字符串是异位字符串的前提1是两字符字符种类数量一样
    	{
    		int len1 = strlen(window);
			int len2 = strlen(p);
			if(len1==len2) //字符串是异位字符串的前提2是两字符字符长度一样
			{
				int flag2 = 0;
				for(int j=0;j<len1;j++)
				{
					if(window[j] != p[j])//字符串是异位字符串的必要条件是两字符字符不能一模一样
					{
						flag2 = 1;
					}
				}
				if(flag2)
				{
					index_arr[x] = left;
					x++;
					flag = 1;
				}
				
			}
			remove_char(window);
    		left++;
    	}
    	right++;
    }
    
    if(flag)
    {
    	for(int i=0;i<x;i++)
    	{
    		if(i != x-1)
    		{
    			printf("%d ",index_arr[i]);
    		}
    		else
    		{
    			printf("%d\n",index_arr[i]);
    		}
    	}
    }
    else
    {
    	printf("没有这样匹配的字符串!\n");
    }
	return 0;	
}

代码版本2:

#include<stdio.h>
#include<string.h>

// 判断字符串s的子串(from left to right)是否包含p的所有字符,并且个数满足要求
int judge_str(int list[],int left,int right, char s[])
{
	int win[128] = { 0 };
	for (int i = left; i <= right; i++)        
	{
		int index = s[i];
		win[index]++;
	}

	for (int i = 0; i < 128; i++)
	{
		if (list[i] != 0 && list[i] > win[i])
		{
			return 0; // 有字符不满足条件,则本子串不满足条件,返回0
		}
	}
	return 1; // 所有字符均满足条件,则本子串满足条件,返回1
}


// 比较s子串(from left to right)与p是否异位,如果异位返回1,否则返回0
int compare_str(char s[],char p[],int left,int right)
{
	for(int i = left,t = 0;i <= right;i++,t++)
	{
		if(s[i] != p[t])
		{
			return 1; // s子串与p存在不同字符 ,那么他们是异位词,返回1
		}
	}
	return 0; // s子串与p全都一样,返回0
}

// 方案主函数,遍历s搜索所有符合条件的子串,将其开始位置存入 position 数组中,并返回是否找到符合条件的子串
int move_window(char s[],char p[], int list[], int size, int position[])
{
	int left = 0;
	int right = size - 1;
	int end = strlen(s) - 1;
	int count = 0;
	int flag = 0;

	while (right <= end &&left <= end && left < right)
	{
		// 判断当前窗口是否满足条件:包含所有p的字符且数量一样
		if(judge_str(list,left,right,s))
		{
			// 如果满足,并且s子串与p是异位词,那么当前窗口符合条件
			if(compare_str(s,p,left,right))
			{
				flag = 1;
				position[count] = left;
				count++;
			}
		}
		// 滑动窗口,准备扫描下个子串
		right++;
		left++;
	}
	position[20101] = count; // 用数组特殊位置存储合适子串个数

	return flag; // 返回是否存在满足条件的子串
}


// 程序的主入口
int main()
{
	// 输入字符串
	char s[20101] = { '\0' };
	char p[20101] = { '\0' };
	int position[20101] = { -1 };

	scanf("%s", s);
	scanf("%s", p);

	// 限制窗口宽度
	int size = strlen(p);
	// 创造p的哈希表,用于后续快速判断子串是否包含所有p的字符
	int list[128] = { 0 };
	for (int i = 0; i < size; i++)
	{
		int index = p[i];
		list[index]++;
	}

	// 寻找符合条件的子串,并返回其开始位置
	int flag = move_window(s,p, list, size, position);

	// 输出结果
	if (flag) // 如果存在满足条件的子串
	{
		int count = position[20101]; // 获取满足条件的子串数量
		printf("count = %d\n",count);
		printf("[");
		for (int i = 0; i < count; i++)
		{
			if (i != count - 1)
			{
				printf("%d, ", position[i]);
			}
			else
			{
				printf("%d]\n", position[i]);
			}
		}
	}
	else // 如果不存在满足条件的子串
	{
		printf("没有这样的子串!\n");
	}
	return 0;
}

问题4:

C代码4:

和前面有一点不一样,主要是窗口移动不太一样。

#include<stdio.h>
#include<string.h>
#define N 80

//向窗口右边添加一个字符,拓宽窗口
void Add_char(char ch,char *window)
{
	int right = strlen(window);
	window[right] = ch;
}
//检查窗口字符串是否满足包含字符串t所有字符且数量不少于t
int Is_ok(char *window)
{
	int windows[128]={0};
	int w=0;
    int len1 = strlen(window);
	for(int i=0;i<len1;i++)
	{
		w = (int)window[i];
		windows[w]++;
	}
	for(int k = 0;k < 128;k++)
	{
		if(windows[k] > 1)
		{
			return 0;//不满足条件
		}
	}
	return 1;//满足条件
}

/*判断当前满足条件的窗口字符串和满足条件的上一次结果字符串比较谁更短,并更新结果。
注意这里不要单纯的把指针result指向新结果(也就是窗口),因为窗口会随着循环而改变,
这样无法保留做中的正确结果,应该把结果字符串赋值给指针result指向的空间*/
void maxlen(char *result,char *window)
{
	int result_len = strlen(result);
	int window_len = strlen(window);
	if(result_len < window_len)
    {
        for(int i = 0;i <= window_len;i++)
        {
            result[i] = window[i];
        }
    }
}

//移除窗口左边第1个字符
void remove_char(char *window)
{
    int len = strlen(window);
	for(int i= 0;i < len;i++)
	{
		window[i] = window[i+1];
	}
}

int main()
{
	//定义所需字符数组
	char s[N];//存储字符串s
	char window[N]={'\0'};//窗口内的字符串
	char result[N]={'\0'};//存储找到的满足条件的最短字符串,这里初始化时将其指向字符串s
	
	//输入字符串s和t
	scanf("%s",s);
	
	//定义滑动窗口所需变量
	int left = 0;//窗口左边界指针
	int right = 0;//窗口右边界指针
	int end = strlen(s);//字符串s的长度,窗口滑动的终止点
	//开始滑动窗口寻找满足条件的最短字符串
    int flag = 0;
	while(right < end)
	{
		Add_char(s[right],window);//拓宽窗口右边界
		if(Is_ok(window)&&left < end)//窗口满足条件,已包含字符串t所有字符且数量也不少
		{
            flag = 1;
			maxlen(result,window);//更新最短满足条件子串答案
        }
        else
        {
        	remove_char(window);//移除窗口左边第1个字符
			left++;//窗口左边界边界向前滑动
		}
		right++;
	}
	
    if(flag)
    {
        printf("%d\n",strlen(result));
    }
    else
    {
        printf("No such string!\n");
    }
    
	return 0;
}

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuga...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值