原題連結:https://www.luogu.com.cn/problem/P4375
題意解讀:計算雙向氣泡排序一共要進行多少趟。
解題思路:一道思維難度較大的題!
由於資料各不相同,先將其離散化處理從1~n的數,如果每個數不在自己的位置則是無序。
對於雙向氣泡排序,對於第x個位置來說,每一趟正向一定會有一個大於x的數交換到x的後,每一趟反向會有一個小於x的數交換到x前面
因此一共要進行多少趟上述過程?取決於對於每一個位置x,從1~x有多少個數大於x,取最大的個數即可。
這裡的關鍵在於如何統計每個位置前有多少個數大於x!
一種O(n)方法:
設cnt表示截止當前位置有多少個數大於當前位置編號
列舉1~n的位置x
對於每一個位置的數num[x],如果num[x]>x,則cnt++
如果x在前面位置作為數值訪問過,則當時肯定導致了cnt++,此時必須cnt--,因為此時位置變成x,前面的數值x不能大於x了
標記num[x]已訪問過
更新答案ans = max(ans, cnt)
注意:如果已經排好序,至少要進行一趟,ans初始值為1。
100分程式碼:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
int n;
bool vis[N];
struct node
{
int val, id;
} a[N];
bool cmp1(node a, node b)
{
return a.val < b.val;
}
bool cmp2(node a, node b)
{
return a.id < b.id;
}
int main()
{
cin >> n;
for(int i = 1; i <= n; i++) cin >> a[i].val, a[i].id = i;
sort(a + 1, a + n + 1, cmp1);
for(int i = 1; i <= n; i++) a[i].val = i; //離散化
sort(a + 1, a + n + 1, cmp2); //恢復原順序
int ans = 1;
int cnt = 0; //當前位置i~1有多個數大於i
for(int i = 1; i <= n; i++)
{
if(a[i].val > i) cnt++;
if(vis[i]) cnt--; //i在前面數字出現過,說明當時肯定導致cnt++,到第i個的時候之前出現的數字i效果就不再,就要cnt--
vis[a[i].val] = true;
ans = max(ans, cnt);
}
cout << ans;
return 0;
}