AcWing刷题(第二周)(链表,单调栈等......)

1:数组元素的目标和

 首先是暴力做法:

暴力做法就是遍历两个数组,如果相加为x,那么就输出这个i和j

 然后介绍的是双指针算法

#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N],n,m,x;

int main(void)
{
    scanf("%d %d %d",&n,&m,&x);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    for(int i=0;i<m;i++) scanf("%d",&b[i]);
    
    for(int i=0,j=m-1;i<n;i++)
    {
        while(a[i]+b[j]>x) j--;
        if(a[i]+b[j]==x)
        {
            printf("%d %d\n",i,j);
        }
    }
    return 0;
}

 也可以使用二分查找来解题:依次遍历a数组,然后通过a数组当前的值来反解出来符合条件的值,然后在b数组中看是否可以找到

#include<iostream>
using namespace std;
const int N=100010;
int a[N],b[N],n,m,x;

int main(void)
{
    scanf("%d %d %d",&n,&m,&x);
    for(int i=0;i<n;i++) scanf("%d",&a[i]);
    for(int i=0;i<m;i++) scanf("%d",&b[i]);
    
    for(int i=0;i<n;i++)
    {
        int y=x-a[i];
        int l=0,r=m-1;
        while(l<=r)
        {
            int mid=l+r>>1;
            if(b[mid]==y)
            {
                printf("%d %d",i,mid);
                return 0;
            }else if(b[mid]<y)
            {
                l=mid+1;
            }else
            {
                r=mid-1;
            }
        }
    }
    return 0;
}

2.区间和

 

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int N = 1000010;
typedef pair<int, int>PII;
vector<PII>query, add;//询问区间还有需要增加的
vector<int>alls;
int a[N], s[N];//s[N]为前缀和
int n, m, l, r, c, x;

int find(int x)
{
	int l = 0, r = alls.size() - 1;
	while (l < r)
	{
		int mid = l + r >> 1;
		if (alls[mid] >= x)
		{
			r = mid;
		}
		else
		{
			l = mid + 1;
		}
	}
	return l + 1;
}

int main(void)
{
	scanf("%d %d", &n, &m);
	for (int i = 0; i < n; i++)
	{
		scanf("%d %d", &x, &c);
		add.push_back({ x,c });
		alls.push_back(x);
	}
	for (int i = 0; i < m; i++)
	{
		scanf("%d %d", &l, &r);
		query.push_back({ l,r });
		alls.push_back(l);
		alls.push_back(r);
	}
	//对所有的区间进行排序,然后进行去重,离散化
	sort(alls.begin(), alls.end());
	alls.erase(unique(alls.begin(), alls.end()), alls.end());
	for (auto tmp : add)
	{
		int x = find(tmp.first);
		a[x] += tmp.second;
	}
	//求前缀和
	for (int i = 1; i <= alls.size(); i++)
	{
		s[i] = s[i - 1] + a[i];
	}
	//求区间和
	for (auto tmp : query)
	{
		int l = find(tmp.first), r = find(tmp.second);
		printf("%d\n", s[r] - s[l - 1]);
	}
	return 0;
}

 3.双链表

 首先我们约定链表头是0,尾是1,这里说的都是下标

所以先对链表进行初始化

然后是插入操作:

 删除操作就很简单了:

	r[l[k]] = r[k];
	l[r[k]] = l[k];
#include<iostream>
using namespace std;
int m;
const int N = 100010;
int e[N], r[N], l[N], idx;

void init()
{
	r[0] = 1;
	l[1] = 0;
	idx = 2;
}

void add(int k, int x)
{
	e[idx] = x;
	r[idx] = r[k];
	l[idx] = k;
	l[r[k]] = idx;
	r[k] = idx;
	idx++;
}

void move(int k)
{
	r[l[k]] = r[k];
	l[r[k]] = l[k];
}

int main(void)
{
	cin >> m;
	init();
	while (m--)
	{
		string op;
		cin >> op;
		int k, x;
		if (op == "R")
		{
			cin >> x;
			add(l[1], x);
		}
		else if (op == "L")
		{
			cin >> x;
			add(0, x);
		}
		else if (op == "D")
		{
			cin >> k;
			move(k + 1);
		}
		else if (op == "IL")
		{
			cin >> k >> x;
			add(l[k + 1], x);
		}
		else {
			cin >> k >> x;
			add(k + 1, x);
		}
	}
	for (int i = r[0]; i != 1; i = r[i])
	{
		cout << e[i] << " ";
	}
	return 0;
}

4:单调栈

暴力解法:从当前位置依次往前遍历,看是否有满足条件的数,有就输出,没有就输出-1

当我们遍历了前面的数,可以利用已知信息来减少遍历次数

思路:

#include<iostream>
using namespace std;
const int N=100010;
int stk[N],m,x,tt;

int main(void)
{
    scanf("%d",&m);
    while(m--)
    {
        scanf("%d",&x);
        while(stk[tt]>=x&&tt)
        {
            tt--;
        }
        if(tt) printf("%d ",stk[tt]);
        else printf("-1 ");
        stk[++tt]=x;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/AkieMo/article/details/128438359