算法笔记5——补充

约瑟夫问题

f(1,1) = 0 + 1;
f(n,k) = ( f(n-1,k) + k )%n + 1;

#include<cstdio>
int n,k;
int main(){
 scanf("%d%d",&n,&k);
 if(n==0){
  printf("0");  return 0;
 }
 int ans=0;
 for(int i=2;i<=n;i++)
  ans=(ans+k)%i;
 printf("%d",ans+1);
 return 0;
离散化

将任何不在合适区间的整数或者非整数转化为不超过元素大小的整数

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=10010;
struct Node{
	int val,pos;
}temp[maxn];
int A[maxn];//存放离散化之后的原始函数
bool cmp(Node a,Node b){
	return a.val<b.val;
}
int main(){
	int n=0;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d",&temp[i].val);
		temp[i].pos=i;
	}
	sort(temp,temp+n,cmp);
	for(int i=0;i<n;i++){
		if(i==0||temp[i].val!=temp[i-1].val)
			A[temp[i].pos]=i+1;
		else
			A[temp[i].pos]=A[temp[i-1].pos];
	}
	for(int i=0;i<n;i++)	printf("%d ",A[i]);
	return 0;
}
n个数的全排列
  • 不含相同元素(dfs法)
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector< vector<int> > ans;
vector<int> tmp;
int n,num[1000];
bool vis[1000]={false};
void dfs4(int u){
	if(u==n){
		ans.push_back(tmp);
		return ;
	}
	for(int i=0;i<n;i++){
		if(!vis[i]){
			//path[u]=num[i];
			tmp.push_back(num[i]);
			vis[i]=true;
			dfs4(u+1);
			tmp.pop_back();
			vis[i]=false;
		}
	}
}
int main(){
	scanf("%d%d",&n,&tg);
	for(int i=0;i<n;i++)
		scanf("%d",&num[i]);
	sort(num,num+n);
	dfs4(0);
	for(int i=0;i<ans.size();i++){
		for(int j=0;j<ans[i].size();j++)
			printf("%d  ",ans[i][j]);
		printf("\n");
	}
	return 0;
}
  • 含有重复元素
void dfs3(int u){
	if(u==n){
		ans.push_back(tmp);
		return ;
	}
	for(int i=0;i<n;i++){
		//将重复元素当作一个元素处理,只有在它之前的重复元素已经被访问,他才可以访问
		if(i==0||num[i-1]!=num[i]||num[i-1]==num[i]&&vis[i-1]){
			if(!vis[i]){
				vis[i]=true;
				tmp.push_back(num[i]);
				dfs3(u+1);
				tmp.pop_back();
				vis[i]=false;
			}
		}
	}
}
  • n个数的全排列(SLT)
#include<cstdio>
#include<algorithm>
using namespace  std;
int main(){
	int n,a[1000];
	scanf("%d",&n);
	for(int i=0;i<n;i++)	scanf("%d",&a[i]);
	sort(a,a+n);
	do{
		for(int i=0;i<n;i++)	printf("%d ",a[i]);
		printf("\n");
	}while(next_permutation(a,a+n));
	return 0;
}
单调队列

参考:单调队列的deque实现
单调队列常用于解决滑动窗口中的最值问题

vector<int> maxSlidingWindow(vector<int>& num, int k) {
	vector<int> res;
	int n=nums.size();
	deque<int> q;
	for(int i=0;i<n;i++){
		while(!q.empty()&&i-q.front>=k)	q.pop_front();//删除越界元素
		while(!q.empty()&&nums[i]>=nums[q.back()])	q.pop_back();//保持队列为递减数列
		q.push_back(i);
		if(i>=k-1)//达到k的窗口大小
			res.push_back(nums[q.front()]);
	}
	return res;
}
  • 区间长度不大于m的最大序列和
#include<cstdio>
#include<deque>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int a[N],sum[N];
struct node{
    int order;  int value;
}tmp;

deque<node> q;
int main(){
	int n,m,ans;
	while(1==1){
		q.clear();
	scanf("%d%d",&n,&m);
	for(int i=0;i<n;i++){
		scanf("%d",&a[i]);
		if(i==0)	sum[i]=a[i];
		else	sum[i]=sum[i-1]+a[i];
		if(!q.empty()&&i-q.front().order>m)
			q.pop_front();//>m
		while(!q.empty()&&q.back().value>sum[i])
			q.pop_back();//必须保证队首的sum最小
		tmp.value=sum[i];
		tmp.order=i;
		q.push_back(tmp);
		if(i==0)	ans=sum[i];
		else	ans=max(ans,sum[i]-q.front().value);
	}
	printf("%d",ans);}
	return 0;
}
单调栈

利用单调栈,可以找到从左/右遍历第一个比它小/大的元素的位置。例如,在递增栈中,元素向左遍历的第一个比它小的数的位置就是将它插入单调栈时栈顶元素的值,若栈为空,则说明不存在这么一个数。

例题:给定两个没有重复元素 的数组 nums1 和 nums2 ,其中nums1 是 nums2 的子集。找到 nums1 中每个元素在 nums2 中的下一个(右边第一个)比其大的值。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/next-greater-element-i

#include<cstdio>
#include<map>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=10000;
int num1[maxn],num2[maxn],n1,n2;
stack<int> st;//栈顶为最小元素
map<int,int> mp;//元素-》较大值
int main(){
	scanf("%d%d",&n1,&n2);
	for(int i=0;i<n1;i++)
		scanf("%d",&num1[i]);
	for(int i=0;i<n2;i++)
		scanf("%d",&num2[i]);
	for(int i=0;i<n2;i++){
		while(!st.empty()&&num2[i]>st.top()){
			mp[st.top()]=num2[i];
			st.pop();
		}
		st.push(num2[i]);
	}
	for(int i=0;i<n1;i++)
		printf("%d  ",mp[num1[i]]);
	return 0;
}
dfs应用
  • 和为tg的组合数(序列中不含重复元素,每个数只能取一次)
#include<cstdio>
#include<vector>
#include<algorithm>
using namespace std;
vector< vector<int> > ans;
vector<int> tmp;
int n,num[1000],tg;
void dfs2(int index,int sum){//dfs2(0,0);
	if(sum==tg){
		ans.push_back(tmp);
		return ;
	}else if(index==n||sum>tg){
		return ;
	}else{
		tmp.push_back(num[index]);
		dfs2(index+1,sum+num[index]);///111111111
		tmp.pop_back();
		dfs2(index+1,sum);
	}
}

!!!若可以多次取数字,则(1)处改为dfs2(index,sum+num[index]);

  • 和为tg的组合数(序列中含重复元素,一个元素取一次)
void dfs1(int index,int sum){
	if(sum==tg){
		ans.push_back(tmp);
		return ;
	}else if(sum>tg){
		return ;
	}else{
		for(int i=index;i<n;i++){
			if(i&&i>index&&num[i-1]==num[i])//将重复情况进行剪枝
				continue;
			tmp.push_back(num[i]);
			dfs1(i+1,sum+num[i]);
			tmp.pop_back();
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值