雙指標習題:Kalindrome Array

Tomorrowland_D發表於2024-10-17

Kalindrome Array

題目連結:

Kalindrome Array - 洛谷 | 電腦科學教育新生態 (luogu.com.cn)

題面翻譯

對於長度為 \(m\) 的序列 \(b\),我們稱 \(b\) 是「迴文的」,當且僅當對於所有 \(i\in[1,m]\),都有 \(b_i=b_{m-i+1}\)。特別的,空序列也是迴文的。

對於一個序列,我們稱其是「可愛的」,當且僅當且滿足如下條件:

  • 存在數 \(x\),使得刪除序列中若干值等於 \(x\) 的元素後,序列是迴文的。(刪除元素後,剩餘元素會並在一起)

需要注意的是,你並不需要刪除所有值等於 \(x\) 的元素,並且,你也可以選擇不刪除任何元素。

例如:

  • \([1,2,1]\) 是可愛的,因為你不需要刪除任何一個數,其本身就是迴文的。
  • \([3,1,2,3,1]\) 是可愛的,因為你可以選擇 \(x=3\),然後刪除所有值等於 \(3\) 的元素,將其變為迴文的。
  • \([1,2,3]\) 則不是可愛的。

現在藍給出了一個長度為 \(n\) 的序列 \(a\),她希望你能幫她確定其是否是可愛的。

本題多組資料,資料組數為 \(t\),會在輸入的開頭給出。對於每組資料,如果給出的序列 \(a\) 是可愛的,請輸出 YES,否則輸出 NO

題目資料滿足:\(1 \leq t \leq 10^4\)\(1 \leq n \leq 2\times10^5\)\(1 \leq a_i \leq n\)\(1 \leq \sum n \leq 2\times10^5\)

題目描述

An array $ [b_1, b_2, \ldots, b_m] $ is a palindrome, if $ b_i = b_{m+1-i} $ for each $ i $ from $ 1 $ to $ m $ . Empty array is also a palindrome.

An array is called kalindrome, if the following condition holds:

  • It's possible to select some integer $ x $ and delete some of the elements of the array equal to $ x $ , so that the remaining array (after gluing together the remaining parts) is a palindrome.

Note that you don't have to delete all elements equal to $ x $ , and you don't have to delete at least one element equal to $ x $ .

For example :

  • $ [1, 2, 1] $ is kalindrome because you can simply not delete a single element.
  • $ [3, 1, 2, 3, 1] $ is kalindrome because you can choose $ x = 3 $ and delete both elements equal to $ 3 $ , obtaining array $ [1, 2, 1] $ , which is a palindrome.
  • $ [1, 2, 3] $ is not kalindrome.

You are given an array $ [a_1, a_2, \ldots, a_n] $ . Determine if $ a $ is kalindrome or not.

輸入格式

The first line contains a single integer $ t $ ( $ 1 \le t \le 10^4 $ ) — the number of test cases. The description of the test cases follows.

The first line of each test case contains a single integer $ n $ ( $ 1 \le n \le 2 \cdot 10^5 $ ) — the length of the array.

The second line of each test case contains $ n $ integers $ a_1, a_2, \ldots, a_n $ ( $ 1 \le a_i \le n $ ) — elements of the array.

It's guaranteed that the sum of $ n $ over all test cases won't exceed $ 2 \cdot 10^5 $ .

輸出格式

For each test case, print YES if $ a $ is kalindrome and NO otherwise. You can print each letter in any case.

樣例 #1

樣例輸入 #1

4
1
1
2
1 2
3
1 2 3
5
1 4 4 1 4

樣例輸出 #1

YES
YES
NO
YES

提示

In the first test case, array $ [1] $ is already a palindrome, so it's a kalindrome as well.

In the second test case, we can choose $ x = 2 $ , delete the second element, and obtain array $ [1] $ , which is a palindrome.

In the third test case, it's impossible to obtain a palindrome.

In the fourth test case, you can choose $ x = 4 $ and delete the fifth element, obtaining $ [1, 4, 4, 1] $ . You also can choose $ x = 1 $ , delete the first and the fourth elements, and obtain $ [4, 4, 4] $ .

思路講解:

我們首先有一個特例:當原序列是迴文序列時,不需要刪除任何數字,它本身就是”可愛的“。

這時,我們只需要寫出判斷一個字串序列是否是迴文序列即可。

我們採用雙指標法對陣列進行迴文序列判斷

bool ishuiwen(int n, int b[])
{
    //若i和n-i+1對應數值不同,肯定不是迴文序列
	for (int i = 1; i <= n; i++) {
		if (b[i] != b[n - i + 1]) return false;
	}
	return true;
}

然後,我們就來處理普遍情況,也是採用雙指標的辦法,從陣列的兩頭出發,檢查對稱位置是否有不相同的元素,

根據題意,我們遇見不相同元素時,可以任意刪除其中的一個元素,以陣列[3,1,2,3,1]為例,我們刪除一個數字,我們如果刪除所有等於這個數字的值以後,如果是迴文的,那刪除這個數字的某些值一定是迴文的。比如,這裡的3和1位置不同,如果我們刪除某些3以後得到的序列是迴文序列,那麼我們刪除所有的3以後得到的序列一定是迴文序列,反之同理,即:如果我們刪除所有的3以後,得到的序列不是迴文序列,那麼我們刪除某些數量的3得到的序列肯定不是迴文序列,這個因為迴文序列的性質,一個序列如果是迴文的話,那麼對應位置的元素肯定是偶數次出現的,我們講這個數字全部刪掉以後,這個數字出現的次數為0次,也是偶次。

懂得這個道理以後,我們只需要使用雙指標遍歷陣列,碰見對應位置不相同的元素,我們就試著刪除陣列中所有值等於這個元素的元素,比如這裡的3和1,是對稱位置,並且數值不同,我們只需要嘗試著將所有的3刪除,檢查是否是迴文序列,或者刪除所有的1,檢查是否是迴文序列,這兩種情況只要有一種滿足迴文序列,那這個字串就是”可愛的“

這裡我們需要使用一個新的陣列來儲存刪除了元素後的新的陣列,定義為tmp。

其它要注意的細節都在註釋中詳細描述了。

程式碼:

#include<iostream>
#include<cstring>
using namespace std;
//預處理n的最大值,這是一個好習慣
const int N = 2e5 + 10;
int a[N], tmp[N];
//檢查一串數是否是迴文序列
bool ishuiwen(int n, int b[])
{
	for (int i = 1; i <= n; i++) {
		if (b[i] != b[n - i + 1]) return false;
	}
	return true;
}
//檢查a陣列中刪除數字x以後得到的新序列是否是迴文序列
bool check(int x, int n)
{

	//作為新陣列tmp的下標
	int index = 0;
	for (int i = 1; i <= n; i++) {
		//如果a中的元素不等於x,我就把a中的值複製到tmp中
		//這裡我使用的是++index,因為acm模式中習慣以1開頭,所以我將0的位置捨棄不用了
		if (a[i] != x) tmp[++index] = a[i];
	}
	//檢查新序列是否是迴文序列
	return ishuiwen(index, tmp);
}
void solve() {
	int n; cin >> n;
	//每次進入測試樣例後清空a陣列,這是一個好習慣
	memset(a, 0, sizeof(a)); memset(tmp, 0, sizeof(tmp));
	for (int i = 1; i <= n; i++) cin >> a[i];
	//如果原陣列就是迴文序列,直接輸出YES,進入下一輪迴圈
	if (ishuiwen(n, a)) {
		cout << "YES" << endl;
		return;
	}
	//雙指標,檢查對稱序列有哪些位置的值不相同
	int l = 1, r = n, x = 1, y = r;
	while (l <= r) {
		//如果檢查到了不相同的值,直接記錄下他們的值,然後退出查詢
		if (a[l] != a[r]) {
			x = a[l], y = a[r];
			break;
		}
		l++; r--;
	}
	//只需要刪除一個位置的值後,變成了迴文序列,那麼a陣列就是“可愛的”
	if (check(x, n) || check(y, n)) {
		cout << "YES" << endl;
	}
	else cout << "NO" << endl;
	return;
}
int main()
{
	int t; cin >> t;
	while (t--) solve();
	return 0;
}

相關文章