1. 程式人生 > >Acient Cipher 古老的密碼 快速排序法

Acient Cipher 古老的密碼 快速排序法

UVa1339(古老的密碼)

題目:古老的密碼
題目描述:
給定兩個長度一樣且不超過100的字串,判斷是否能把其中一個字串的各個字母重排,之後對26個字母做一個一一對映,使得兩個字串相同
例如,JWPUDJSTVP重排後可以得到WJDUPSJPVT,之後把每個字母對映到它的前面一個字母,得到VICTORIOUS,輸入兩個字串,輸出YES或者NO
題目分析:
因為字母可以重排,每個字母的位置並不重要,重要的是每個字母出現的次數
①統計兩個字串每個字母出現的次數,得到兩個陣列cnt1[26],cnt2[26]
②之後我們排序下,排序之後結果相同,說明我們輸入的兩個字串就可以通過重排一一對映變得相同了所以本道題的核心在與【排序】
學習筆記:


關於排序
C語言中stdlib.h中又一個叫qsort的庫函式,
qsort的宣告void qsort(void base, size_t num, size_t size, int(cmp)(const void , const void ));
如果排序是整型陣列的話,
int cmp(const void a, const void b)
{
return (int )a - (int )b;
}
②c++中又一個函式sort更加常用些,標頭檔案#include<algorithm>
預設sort是按升序排列,sort(a,a+n) 兩個引數分別為待排序陣列的首地址和尾地址
也可以寫一個判定函式,按照自己的意願排列
bool compare(const int a, const int b)
{
return a < b;
}

==============================================================================

以上是我查閱的資料,除此以外,我還深刻的理解了一下快速排序法

資料如下:

快速排序由於排序效率在同為O(N*logN)的幾種排序方法中效率較高,因此經常被採用,再加上快速排序思想----分治法也確實實用,因此很多軟體公司的筆試面試,包括像騰訊,微軟等知名IT公司都喜歡考這個,還有大大小的程式方面的考試如軟考,考研中也常常出現快速排序的身影。

總的說來,要直接默寫出快速排序還是有一定難度的,因為本人就自己的理解對快速排序作了下白話解釋,希望對大家理解有幫助,達到快速排序,快速搞定。

快速排序是C.R.A.Hoare1962年提出的一種劃分交換排序。它採用了一種分治的策略,通常稱其為分治法(Divide-and-ConquerMethod)

該方法的基本思想是:

1.先從數列中取出一個數作為基準數。

2.分割槽過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。

3.再對左右區間重複第二步,直到各區間只有一個數。

雖然快速排序稱為分治法,但分治法這三個字顯然無法很好的概括快速排序的全部步驟。因此我的對快速排序作了進一步的說明:挖坑填數+分治法:

先來看例項吧,定義下面再給出(最好能用自己的話來總結定義,這樣對實現程式碼會有幫助)。

以一個數組作為示例,取區間第一個數為基準數。

0

1

2

3

4

5

6

7

8

9

72

6

57

88

60

42

83

73

48

85

初始時,i = 0;  j = 9;   X = a[i] = 72

由於已經將a[0]中的數儲存到X中,可以理解成在陣列a[0]上挖了個坑,可以將其它資料填充到這來。

j開始向前找一個比X小或等於X的數。當j=8,符合條件,將a[8]挖出再填到上一個坑a[0]中。a[0]=a[8]; i++;  這樣一個坑a[0]就被搞定了,但又形成了一個新坑a[8],這怎麼辦了?簡單,再找數字來填a[8]這個坑。這次從i開始向後找一個大於X的數,當i=3,符合條件,將a[3]挖出再填到上一個坑中a[8]=a[3]; j--;

陣列變為:

0

1

2

3

4

5

6

7

8

9

48

6

57

88

60

42

83

73

88

85

i = 3;   j = 7;   X=72

再重複上面的步驟,先從後向前找,再從前向後找

j開始向前找,當j=5,符合條件,將a[5]挖出填到上一個坑中,a[3] = a[5]; i++;

i開始向後找,當i=5時,由於i==j退出。

此時,i = j = 5,而a[5]剛好又是上次挖的坑,因此將X填入a[5]

陣列變為:

0

1

2

3

4

5

6

7

8

9

48

6

57

42

60

72

83

73

88

85

可以看出a[5]前面的數字都小於它,a[5]後面的數字都大於它。因此再對a[0…4]a[6…9]這二個子區間重複上述步驟就可以了。

對挖坑填數進行總結

1.i =L; j = R; 將基準數挖出形成第一個坑a[i]

2.j--由後向前找比它小的數,找到後挖出此數填前一個坑a[i]中。

3.i++由前向後找比它大的數,找到後也挖出此數填到前一個坑a[j]中。

4.再重複執行23二步,直到i==j,將基準數填入a[i]中。


趁熱打鐵,自己實現了快速排序法:

demo:

void quick_sort(int s[], int l; int r)
{
    if(l < r)
    {
        int i = l, j = r, X = s[l];

        while(i < j) 
	{
	    while(i < j && s[j] >= X)
	    {
	        j--;
	    }
	    if(i < j) s[i++] = s[j];

	    while(i < j && s[i] < X)
	    {
	        i++;
	    }
	    if(i < j) s[j--] = s[i];
        }
	s[i] = X;
        quick_sort(s, l, i - 1);
	quick_sort(s, i + 1, r);
    }	
}

扯了一大堆,本題的demo如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define maxn 100+10

int cmp(const void *a,const void *b)
{
    return *(int *)a - *(int *)b;
}

int main()
{
    char a[maxn];
    char b[maxn];

    while(scanf("%s%s",a,b) != EOF)
    {
        int len = strlen(a);
	int cnt1[26],cnt2[26];

	memset(cnt1,0,sizeof(cnt1));
	memset(cnt2,0,sizeof(cnt2));

	int i;
	for(i = 0; i < len; i++)
	{
	    cnt1[a[i] - 'A']++;
	    cnt2[b[i] - 'B']++;
	}

	qsort(cnt1,26,sizeof(cnt1[0]),cmp);
	qsort(cnt2,26,sizeof(cnt2[0]),cmp);

	for(i = 0; i < 26; i++)
        {
	    if(cnt1[i] != cnt2[i])
	    {
	        printf("NO\n");
		return 0;
	    }
	}
	printf("YES\n");
    }
    return 0;
}

我自己理解這道題,最大的瓶頸是:排序之後結果相同,說明我們輸入的兩個字串就可以通過重排一一對映變得相同了

思考加上討論了許久,才悟出其中道理,甚為精妙啊