1067. Sort with Swap(0,*) (25)

来源:互联网 发布:知乎 张艺兴 编辑:程序博客网 时间:2024/06/03 18:59

Given any permutation of the numbers {0, 1, 2,…, N-1}, it is easy to sort them in increasing order. But what if Swap(0, *) is the ONLY operation that is allowed to use? For example, to sort {4, 0, 2, 1, 3} we may apply the swap operations in the following way:

Swap(0, 1) => {4, 1, 2, 0, 3}
Swap(0, 3) => {4, 1, 2, 3, 0}
Swap(0, 4) => {0, 1, 2, 3, 4}

Now you are asked to find the minimum number of swaps need to sort the given permutation of the first N nonnegative integers.

Input Specification:

Each input file contains one test case, which gives a positive N (<=105) followed by a permutation sequence of {0, 1, …, N-1}. All the numbers in a line are separated by a space.

Output Specification:

For each case, simply print in a line the minimum number of swaps need to sort the given permutation.

Sample Input:
10 3 5 7 2 6 4 9 0 8 1
Sample Output:

这里我先贴一下我写的程序吧,但是两个测试点超时了。

#include<bits/stdc++.h>using namespace std;int sum;int xiugai(vector<int> &jt, int n){    int i;    int temp;    for (i = 1; i < n ; i++)        {            if (jt[i] != i) break;        }        if (i == n)        {            cout << sum;            exit(0);        }        else        {            temp = jt[i];            jt[i] = 0;            jt[0] = temp;            sum ++;        }        return i;}int main(void){    int n;    cin >> n;    if (n == 0)     {        cout << "0";        return 0;    }    vector<int> jt(n);    int i, temp;    for (i = 0; i < n; i++)    {        cin >> jt[i];    }    if (jt[0] == 0)    {        for (i = 1; i < n ; i++)        {            if (jt[i] != i) break;        }        if (i == n)        {            cout << sum;            return 0;        }        else        {            temp = jt[i];            jt[i] = 0;            jt[0] = temp;            sum ++;        }    }    int index1, tmp, index2;    for (i = 0; i < n; i++)        {            if (jt[i] == 0) break;        }        if (i == 0)        {             index1 = xiugai(jt, n);             tmp = index1;        }        else        {            index1 = i;            tmp = i;            }        for (i = 0; i < n; i++)            {                if (jt[i] == tmp) break;            }            index2 = i;            jt[index2] = 0;            jt[index1] = tmp;            sum++;    for(;;)    {        if (index2 == 0)        {            index1 = xiugai(jt, n);            tmp = index1;           }        else        {            index1 = index2;            tmp = index2;        }                for (i = 0; i < n; i++)            {                if (jt[i] == tmp) break;            }            index2 = i;            jt[index1] = tmp;            jt[index2] = 0;            sum++;            if (i == n)            {                cout << sum;                break;            }    }     return 0;}/* 10 9 8 7 6 5 4 3 2 1 0*/

为什么会超时呢,原因是,我存储数据的方式是数组下标表示位置,数组元素表示对应位置上的元素。这样一来,每次要去找对应位置的时候(这里算法不仔细分析了,如果连算法都还没想出来的建议去看看别人的博客),就得从第0个位置找到最后一个元素,找出来0所在位置应该在的元素,它的位置在哪里,每次查找需要O(N)复杂度,总共有O(N)个点,所以总的复杂度花了O(N^2),所以有两个点超时。
那么怎么解决呢,这里贴下别人的代码:

#include <stdio.h>  int findNotOK(int* arr,int begin,int end)   //从begin开始往后寻找未到位的数  {      for(int i=begin;i<end;i++)      {          if(arr[i]!=i)return i;      }      return 0;  }  int main()  {      int n;      scanf("%d",&n);      int* arr = new int[n];      int i,t;      for(i=0;i<n;i++)      {          scanf("%d",&t);          arr[t]=i;      }      int tmp = 0;      int count=0;      int firstPos = 1;      firstPos = findNotOK(arr,firstPos,n);      while(firstPos)     //还有未到位的数字      {          if(arr[0]==0)       //如果0到位了,则与未到位的firstPos交换          {              arr[0] = arr[firstPos];              arr[firstPos] = 0;              count++;          }          while(arr[0]!=0)    //如果0不到位,则循环与自己所指向的值交换          {              tmp = arr[0];              arr[0] = arr[tmp];              arr[tmp] = tmp;              count++;          }          firstPos = findNotOK(arr,firstPos,n);       //此时0归位了,找到下一个未到位的数字      }      printf("%d\n",count);      return 0;  } 

我看那个博主并没有对这种存储方式的优点和原因进行分析,所以我这里帮他分析一下。
这里存储我感觉就像是一个哈希表,实际上是一个map。但是c++ map虽然容易理解,但是太容易超时,而且反正只是int -> int的一个映射,直接用基本的数组就可以了.
这里是这么存储数据的:下标表示那个元素,数组元素表示位置,也就是说,比如给一组数据3, 2 1 0
那么就是arr[2] = 0,意思是数字2,它现在的位置是在0。
所以,这个方式的好处就是,你不需要查找了,你直接比如说想知道,5这个元素,它的位置在哪里,你直接arr[5]就直接获得了它的位置。
比如说6个数:6, 1 2 3 4 5 0 现在按照算法,你是要把这列数字的0和5进行一个交换,变成123405,对吧。
那么你直接先找到arr[0] = 5,我们直接找到0现在在数列的第6个地方,然后再temp = arr[0]
,然后再arr[temp]直接找到5这个数在数列的第五个地方,那么我们直接交换,arr[0] = arr[temp],arr[temp] = temp,这样就实现了我们位置的交换。

现在对数据结构的理解越来越深刻了,一个好的数据存储方式,直接导致了你的代码所需要的算法更简单。就像这位博主的代码,我们往往正常思维,数组下标表示位置,数组元素表示你需要存储的数据,但是这里用下标表示你要存储的数据,数组元素来表示位置,这就是代码思维和数据结构的魅力所在吧!

原创粉丝点击