时间复杂度优化

题目链接:蓝桥云课 

1.寻找食物储量

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,x;
int a[1000010];
signed main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>a[i];
	}
	cin>>x;
	auto t=lower_bound(a,a+n,x)-a;
	if(t==n)
	{
		cout<<-1<<endl;	
	}
	else
	{
		cout<<t+1<<endl;
	}
	return 0;
}

 题目意思告诉你是顺序排序,所以可以联想到二分查找(前提是顺序排序)

2.挑选子串

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,sum1=0;
int a[2010];
signed main()
{
	cin>>n>>m>>k;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
	}
	for(int i=1; i<=n; i++)
	{
		int sum=0; //统计的应该是每个子串满足的个数 
		for(int j=i; j<=n; j++) //遍历所有可能的子串 1,2 1,3 1,,n 
		{
			if((n-i+1)>=k)
			{
				if(a[j]>=m)
				{
					sum++;
				}
			}
			else
			{
				break;
			}
		}
		if(sum>=k) //此处却单单只执行了一次 1,,n
		{
			sum1++;
		}
	}
	cout<<sum1<<endl; 
	return 0;
}

开始的思想,但是出现了问题,之前原来一直没理解此种遍历的所有子串意思,修改后的代码:

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,m,k,sum1=0;
int a[2010];
signed main()
{
	cin>>n>>m>>k;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
	}
	for(int i=1; i<=n; i++)
	{
		int sum=0; //字串中满足条件的个数
		for(int j=i; j<=n; j++)
		{
			if(a[j]>=m)
			{
				sum++;
			}
			if(sum>=k) //长度检查 
			{
				sum1+=(n-j+1); //后续所有子串满足
				break; 
			}
		}
	}
	cout<<sum1<<endl;
	return 0;
}

3.小蓝的漆房

#include<bits/stdc++.h>
#define int long long
using namespace std;
int t;
signed main()
{
	cin>>t;
	while(t--)
	{
		int n,k; //k区间就是滑块移动 
		int a[10010];
		cin>>n>>k;
		memset(a,0,sizeof(a));
		for(int i=1; i<=n; i++)
		{
			cin>>a[i];
		}
		int min1=1e4;
		for(int i=1;i<=60;i++) //暴力遍历所有可能 
		{
			int sum=0,sign=1;
			while(sign<=n)
			{
				if(a[sign]!=i)
				{
					sum++; //需要改漆 
					sign+=k; //滑块移动下一个位置
				}
				else
				{
					sign++; //滑块移动 
				}
			}
			min1=min(min1,sum); 
		}
		cout<<min1<<endl;
	}
	return 0;
}

暴力遍历,区间问题,类似于滑块移动  

4.美丽的区间

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,s;
int a[100010];
signed main()
{
	cin>>n>>s;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	int start=1,end=1,min_len=1e5+2,sum=0;
	for(int end=1;end<=n;end++)
	{
		sum+=a[end];
		while(sum>=s)
		{
			min_len=min(min_len,end-start+1);
			sum-=a[start];
			start++;
		}
	}
	if(min_len!=(1e5+2))
	{
		cout<<min_len<<endl;
	}
	else
	{
		cout<<0<<endl;
	}
	return 0;
}

双指针遍历,优化时间复杂度 

5.赛车游戏

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n;
int a[50010],b[50010];
signed main()
{
	cin>>n;
	for(int i=0; i<n; i++)
	{
		cin>>a[i]>>b[i];
	}
	sort(a,a+n);
	sort(b,b+n);
	int index=n-1,sum=0; //遍历小蓝 
	for(int i=n-1;i>=0;i--) //只能遍历小明,防止一直不满足的情况发生(和力扣分发饼干一个题) 
	{
		if(index>=0 && a[i]<b[index])  //index>=0不要也行,有题目知道index>=0肯定满足 
		{
			index--;
			sum++;
		}
	}
	cout<<sum<<endl;
	return 0;
}

贪心+双指针方法 

6.神奇的数组

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,sum=0;
int a[200010];
signed main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
		int temp=0,temp1=0;
		for(int j=i;j<=n;j++)
		{
			temp^=a[j];
			temp1+=a[j];
			if(temp==temp1)
			{
				sum++;
			}
		}
	}
	cout<<sum<<endl;
	return 0;
}

部分样例通过,时间复杂度超了,改为前缀思想+双指针

#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,sum=0;
int a[200010],sum1[200010],sum2[200010];
signed main()
{
	cin>>n;
	for(int i=1; i<=n; i++)
	{
		cin>>a[i];
	}
	for(int i=1; i<=n; i++) //前缀思想
	{
		sum1[i]=a[i]^sum1[i-1];
		sum2[i]=a[i]+sum2[i-1];
	}
	//双指针
	int i=1,j=1;
	while(i<=n&&j<=n)
	{
		if((sum1[i-1]^sum1[j])==(sum2[j]-sum2[i-1]))
		{
			sum+=j-i+1;
			j++;
		}
		else
		{
			i++;
		}
	}
	cout<<sum<<endl;

	return 0;
}

((sum1[i-1]^sum1[j])==(sum2[j]-sum2[i-1])) 解释:

理解异或的本质和累积性

1. 异或的本质

  • 异或(^)的本质是 模 2 加法,即 不带进位的二进制加法

    • 0 ^ 0 = 0

    • 1 ^ 1 = 0

    • 0 ^ 1 = 1

    • 1 ^ 0 = 1

  • 它与普通加法(+)不同,因为普通加法会发生进位,而异或不会。

2. 异或与普通加法关系的特殊条件

  • 当一个序列从 a[i]a[j]异或和 等于其 普通和 时,说明这个区间的所有数字相加时都 没有进位

    • 例如:数组 [2, 5, 3]

      • 异或和 = 2 ^ 5 ^ 3 = 4

      • 普通和 = 2 + 5 + 3 = 10

      • 不满足等价条件,因为存在进位。

  • 但对于特殊的情况,例如 [1,2,3]

    • 异或和 = 1 ^ 2 ^ 3 = 6

    • 普通和 = 1 + 2 + 3 = 6

    • 满足等价条件,因为没有任何进位。即子序列 1 ^ 2 = 1 + 2

 所以如果 [i, j] 没有进位,那么它的任意子序列也不会产生进位,所以可以直接计算得到: sum+=j-i+1;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值