⑩做對了的題目(1)——全排列

⑩做對了的題目(1)——全排列

5 人贊了文章

這是難度為中等,露米婭自己做出來了的題目~

其實這是全排列問題,應該是很經典的題目,但是露米婭沒接觸過,自己用強行土辦法做出來了……


問題

大家都知道單詞可以按照字典序比較大小吧~就是先按首字元比較,如果首字元相同,再按第二個字元比較,如果第二個字元相同,就按第三個比較,依此類推~

比如說aaa < aab,abz < aca等等,翻一翻字典,看看單詞的排序,大家就會明白了……

那麼,對於一個字元串,將字元串中的字母順序打亂我們就可以得到很多新的字元串。

在這些字元串中,肯定有一些是比原來大的字元串。那麼,你就需要找出它們當中最小的一個,如果不存在這樣的字元串,就返回no awnser。

比如,對於hefg而言,打亂後,有hfeg,hfge,hgef,hgfe,hegf等情況是比原來大的,它們當中最小的是hegf。

HackerRank?

www.hackerrank.com圖標

實現

露米婭是寫了一些情況,才找出規律,想出演算法的……

對於長度為1的,肯定是不存在的。

對於長度為2的,如果第一個字母小於第二個,交換一下就行了,否則,就是不存在,比如ab變ba就可以了,但是對於aa而言,無論怎麼換都是aa,沒有比原來大的情況……

對於長度大於2的,就可以用遞歸的思路了~感覺描述起來有點複雜,就不描述了,大家看我的實現吧~

/*用於qsort*/int comp(const void *a, const void *b){ return *(char *)a - *(char *)b;}/*對於字元串w,找到所有大於ch的字母中,最小的那個字母的指針*/char *findFirstGreater(char *w, int n, char ch){ char min = 127; int min_index = -1; for(int i = 0; i < n; i++){ if(w[i] <= ch) continue; if(w[i] < min){ min = w[i]; min_index = i; } } if(min_index == -1) return NULL; return w + min_index;}/*全排列問題*/char* biggerIsGreater(char* w, int n) { char temp; if(w == NULL) return NULL; if(n < 2) return NULL; if(n == 2){ if(w[0] >= w[1]) return NULL; else { temp = w[0]; w[0] = w[1]; w[1] = temp; return w; } } if(biggerIsGreater(w + 1, n - 1) == NULL){ char *p = findFirstGreater(w+1, n-1, w[0]); if(p == NULL) return NULL; char temp = *w; *w = *p; *p = temp; qsort(w+1, n-1, sizeof(char),comp); } return w;}

這樣就可以了~

題外話

HackerRank會幫你寫好主函數,用於處理輸入輸出,但是主函數有一個問題:

for(int a0 = 0; a0 < T; a0++){ char* w = (char *)malloc(512000 * sizeof(char)); scanf("%s", w); int result_size; char* result = biggerIsGreater(w); printf("%s
", result); }

發現了嗎?調用malloc之後竟然沒有調用free釋放內存……

於是,在一些測試情況中,內存空間被耗盡,導致了段錯誤……

我排查了20分鐘後才發現,我的演算法是沒問題的,問題出在沒有調用free來釋放內存……

於是就AC啦~

如果想要非遞歸的演算法,可以參考

Next lexicographical permutation algorithm?

www.nayuki.io

之後,我對於接近80%的通過率感到好奇,這題竟然有這麼多人做出來了,老外都這麼強的嗎……?

看了一下討論區,原來C++有一個函數next_permuation(),可以直接得出這道問題的結果……

推薦閱讀:

TAG:演算法 | 編程 | C編程語言 |