程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 指定序的排序問題,記一個學生的問題

指定序的排序問題,記一個學生的問題

編輯:C#入門知識

主要內容

 

  最近在傳智論壇遇到一個算法的問題,想了一下,有一個我認為比較有趣的解法. 下面算 法或許不是最優的,但是可以參考一下.

問題:

=======================================================================
給定兩個字符串,僅由小寫字母組成,它們包含了相同字符。求把第一個字符串變
成第二個字符串的最小操作次數,且每次操作只能對第一個字符串中的某個字符移
動到此字符串中的開頭。

例如給定兩個字符串“abcd" "bcad" ,輸出:2,因為需要操作2次才能把"abcd"變
成“bcad" ,方法是:abcd->cabd->bcad。

 

我開始用廣度優先搜索做。可是比如abcdefg 和 gfedcba 遞歸下去就是7的7次方的
時間復雜度 然後再在變換位置的函數裡循環 循環次數報表。

然後我用List記錄 abcdefg出現的東東 把重復的去掉了,也就是7*6*5*4*3*2
但是每次判斷list.contain()在內部貌似又要循環時間和上面差不多.

有沒有比較好的解決方式.

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

這個問題比較有趣,這裡我使用C#來完成,主要是考慮微軟提供了許多數據結構 不用再重新實現數據結構和相關方法了.

問題分析

再將原來的字符串看成一個等待排序的數據結構,就可以將問題簡化為簡單的排序算
法了. 即:指定序的排序問題.

  舉個例子:將字符串"abcd"變成"bcad". 那麼字符集"bcad"構成一個有序集,可以得到映射表,如下:
{ ('b', 0), ('c', 1), ('a', 2), ('d', 3) } 因此需要排序的字符串就變成了一個數字集:{ 2, 0, 1, 3 }. 即 需要將這個數據集排序為 { 0, 1, 2, 3 },需要求最小的步驟. 因
此將問題轉化為排序最小步驟問題.

  另一方面,問題考慮了算法實現的要求,即每次只能將一個數據 取出,插入到開始的地方. 也就是說具體操作就是一個固定的函數:
將第i項插入到0項,原來前i-1項的數據依次後移一位. 故方法很簡單:

  
   jk_remove([] s,       temp =      ( i = index - ; i >= ; i--         s[i + ] =      s[] = }

 


那麼這個函數調用幾次,就表示操作了幾次.
下面考慮另一個問題. 就是什麼時候調用這個函數. 也就是如何操作才算是較優. 這個問題有點麻煩. 起初我打算從現成的算法中找一個. 不過現成的都不太友好. 想到
了使用"逆序"的方法.
所謂最少的步驟. 就是不要移動多余的步驟. 在前面已經提到,問題已經劃歸成排 序問題,下面姑且使用升序.
要將一個數字序列排序,又只能將數據往前放,那麼最小的步驟就是每次移動一個 數據並且這個數據就是一個良序的,也就是說這個數字不會再次移動. 那麼一個長度為
n的字符串,最多移動n-1次. 我想這個應該是最少的步驟了吧!!!
下面看看怎麼移動會比較好.
首先考慮移動的特征就是每次移動數據都放在最開始的地方. 同時下一次移動開始 後這個已經被移動過的數據就會自動擠到後面去. 那麼不再重復移動這個數據的辦法就
是首先移動最大的數. 那麼在移動剩下的最大數,就可以保證移動完成以後結果就是良
序的了.
那麼什麼樣的數據需要移動呢?很簡單逆序(注1)的. 舉個例子:
延續前面的例子,數字2013. 第一個數字不需要考慮,第二個數字0與2構成一個逆 序,因此0是逆序數. 第三個數字1與2構成逆序,即1為逆序數. 那麼首先移動較大的,
移動1得到1203. 由於數據排列發生變化,需要重新計算逆序. 因此得到0為逆序數,移
動0,得到結果0123.
這裡就得到一個結論,就是判斷逆序,移動最大的逆序數即可. 由此得到偽代碼:

 
   jk_sort(      temp = ;         
     ( i = ; i < s.length; i++         ( j = ; j < i; j++             
             (s[i] <                 
                 (temp ==  || temp <                     temp =                  
                         
     (temp !=           
   }        

 

這裡使用了遞歸,算法復雜度提升了,具體的優化可以以後再說. 那麼有了這個思
路以後,就可以實現了.


代碼實現

首先寫一個類

   
 }

 

提供靜態方法,移動數據

    jk_remove([] s,       temp =      ( i = index - ; i >= ; i--         s[i + ] =      s[] = }

 


提供映射,可以考慮使用一個鍵值對

  Dictionary<, > dic; 
  JKSort(     dic =  Dictionary<, >     ( i = ; i < chs.Length; i++   }

 

    internal_jk_sort([] s, Dictionary<, >      temp = -;    
 
     ( i = ; i < s.Length; i++         ( j = ; j < i; j++ 
             (dic[s[i]] < 
                 (temp == - || dic[s[temp]] <                     temp =  
                         
     (temp != -          
   }

 


實現對外公開的方法

    JK_Sort( str,      [] chs =     [] obj = 
     JKSort j =  
  
 
        }

 

那麼就完成了排序. 這裡提供的算法沒有實現優化,如想了解優化與帶有重復字符
串的解決辦法,請等待下文.
睡覺,2013年12月18日凌晨0時.


注1
逆序:在一個數字排列中,如果其中的兩個數前面的一個比後面的一個大,那麼就稱
它們構成一個逆序. 相關逆序的結論與問題,可以參考《高等代數》或《線性代數》
的教材.

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved