双向循环链表模拟:

1.用一个双链表维护块内水果的编号关系。

2.用一个双链表维护块与块之间的水果关系,块的地址用块内最后一个水果编号。

#include<bits/stdc++.h>
using namespace std;

const int N = 2e5 + 10;
int l[N], r[N], bl[N], br[N];  // l,r是块内双链表,bl, br块之间双链表
int w[N];

int main()
{
	freopen("bear.in", "r", stdin);
	freopen("bear.out", "w", stdout);
	int n;
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> w[i];
	int cnt = 0; // 块的数量
	for (int i = 1, last = n; i <= n; i++)
	{
		int j = i + 1;
		while (j <= n && w[i] == w[j]) j++;  // i~j-1连续的一段
		// 建立i~j-1之间块内双向链表
		for (int k = i; k < j; k++) l[k] = k-1, r[k] = k+1;
		l[i] = j-1;
		r[j-1] = i;
		// 建立块与块之间的关系,last代表上一个块的地址,当前块地址为j-1
		br[last] = j-1, bl[j-1] = last;
		last = j-1;
		i = j-1;
		cnt ++;
	}
	
	int head = br[n];  // 最后一个块的右边就是第一个块的末尾编号
	while (true)
	{
		int new_head = -1;
		for (int t = cnt, i = head; t != 0; t--, i = br[i])
		{
			int k = r[i];
			cout << k << " ";
			if (i == k) // 块内只有一个水果
			{
				br[bl[k]] = br[k], bl[br[k]] = bl[k];  // 整块删除
				cnt --;
			}
			else // 块内多个水果
			{
				r[l[k]] = r[k], l[r[k]] = l[k];  // 删除取走的水果
				if (new_head == -1) new_head = i;
			}
		}
		if (cnt == 0) break;
		head = new_head;
		if (cnt > 1) // 可能需要合并,处理合并逻辑
		{
			new_head = -1;
			for (int t = cnt, i = head; t > 1; t --, i = br[i])
			{
				int j = br[i];  // i是当前块,j是下一个块
				if (w[i] == w[j]) // 水果种类相同
				{
					// 合并两个相邻块
					int ri = r[i], rj = r[j];
					r[i] = rj, l[rj] = i;
					l[ri] = j, r[j] = ri;
					
					// 将 i 连到 j,删除i
					bl[br[i]] = bl[i], br[bl[i]] = br[i];
					cnt --;
				}
				else if (new_head == -1) new_head = i;
			}
			if (new_head == -1) new_head = bl[head];
			head = new_head;
		}
		cout << endl;	
	}
	
	return 0;
}

0 条评论

目前还没有评论...

信息

ID
342
时间
1000ms
内存
256MiB
难度
9
标签
递交数
9
已通过
6
上传者