Introdução ao par reverso
Se houver um número inteiro positivo i, j tal que 1 ≤ i <j ≤ n e A [i]> A [j], então o par ordenado de <A [iGirl, A [jorgeous> é chamado par inverso de A, e Chamado o número da ordem inversa.
Resolva o número de pares reversos em uma matriz
De fato, é encontrar um grande número com um pequeno índice, então não vamos falar primeiro sobre violência, a violência é obviamente O (n 2 ), 8 Taihang
int unseq(vector<int> &nums)
{
int cnt = 0;
for(int i=0; i<nums.size(); i++)
for(int j=i+1; j<nums.size(); j++)
if(nums[i]>nums[j]) cnt++;
return cnt;
}
Divida e conquiste o pensamento: classifique por fusão
Para o número de pares na ordem inversa na matriz, divida a matriz em intervalos [l, mid]
AND [mid+1, r]
, e o problema pode ser decomposto em subproblemas:
- Subarray
[l, mid]
inverter o número lcnt [mid+1, r]
Número do par de ordem inversa do subconjunto rcnt- A [i] está à esquerda, A [j] está à direita e o par de <i, j> de A [i]> A [j]
As perguntas 1 e 2 podem ser resolvidas recursivamente, então a chave é como encontrar a pergunta 3, ou seja,
Observe que, ao resolver o problema 12 aqui, não apenas a solução, mas também a matriz é classificada, ou seja, os lados esquerdo / direito estão em um estado ordenado , então podemos usar o tempo O (n) para concluir a solução
- Na sub-matriz direita, enumere j subscritos de trás para frente
- Na sub-matriz esquerda, defina o ponteiro i, no início i aponta para o meio
- i Deslize para a esquerda para encontrar o primeiro i tal que A [i] <= A [j]
- Anterior descrição
i+1 ~ mid
subscrito, a [i] é maior do que A [j] - Em seguida, para A [j] a reverter para a direita, encontrado
mid-i
em
Como os dois lados são ordenados, então para o j subscrito, porque A [j] está diminuindo, então A[j+1]配对的个数,同样可以运用到A[j]
, além disso, devemos julgar adicionalmente se A [j] pode encontrar mais pares de ordem reversa
Aqui , a ordem dos dois lados da matriz é usada e os resultados anteriores são usados disfarçados para economizar tempo
Parece ser um loop duplo; de fato, i, j não volta mais de n / 2 vezes, portanto a complexidade é O (n)
Usando o tempo O (n) para encontrar o número de pares na ordem inversa, também precisamos mesclar a matriz para facilitar a recursão anterior para continuar a pesquisa
Use [ função inplace_merge ] para operação de mesclagem
Você pode ter muitos pontos de interrogação aqui:
Após a classificação, o pedido não é interrompido?
Antes de embaralhar a ordem (classificação), obtivemos o número de soluções dos sub-arranjos em ambos os lados
e , ao resolver o par reverso da cruz , a esquerda e a direita são classificadas, mas suas posições relativas permanecem inalteradas , ou seja, o elemento esquerdo Subarray à esquerda, o mesmo à direita
int unseq(vector<int> &nums, int l, int r)
{
if(l>=r || l<0 || r>=nums.size()) return 0;
int mid=(l+r)/2, cnt=0, i=mid;
int lcnt = unseq(nums, l, mid);
int rcnt = unseq(nums, mid+1, r);
for(int j=r; j>mid; j--)
{
while(i>=l && nums[j]<nums[i]) i--;
cnt += mid-i;
}
inplace_merge(nums.begin()+l, nums.begin()+mid+1, nums.begin()+r+1);
return lcnt+rcnt+cnt;
}
Código completo
#include <bits/stdc++.h>
using namespace std;
int unseq(vector<int> &nums, int l, int r)
{
if(l>=r || l<0 || r>=nums.size()) return 0;
int mid=(l+r)/2, cnt=0, i=mid;
int lcnt = unseq(nums, l, mid);
int rcnt = unseq(nums, mid+1, r);
for(int j=r; j>mid; j--)
{
while(i>=l && nums[j]<nums[i]) i--;
cnt += mid-i;
}
inplace_merge(nums.begin()+l, nums.begin()+mid+1, nums.begin()+r+1);
return lcnt+rcnt+cnt;
}
int unseq(vector<int> &nums)
{
int cnt = 0;
for(int i=0; i<nums.size(); i++)
for(int j=i+1; j<nums.size(); j++)
if(nums[i]>nums[j]) cnt++;
return cnt;
}
int main()
{
vector<int> nums{2,7,4,3,1,8,6,5};
cout<<unseq(nums)<<endl;
cout<<unseq(nums, 0, nums.size()-1)<<endl;
for(int i=0; i<nums.size(); i++) cout<<nums[i]<<" ";
cout<<endl;
return 0;
}