微軟筆試題——基數排序
阿新 • • 發佈:2018-12-25
這是一題微軟的筆試題,原題如下:
排序N個比N^7小的數,要求的演算法是O(n)(給了提示..說往N進位制那方面想)
此題的分析見 http://blog.csdn.net/sinshine/article/details/6844370
本人使用了N進位制的做法,當然在程式中涉及到了十進位制字串轉化為N進位制的整數(一個數組)和N進位制整數轉化為十進位制字串。修改之後的演算法複雜度是O(n)級別的,因為將一個十進位制整數字符串轉化為N進位制的整數是常數的(注意在本題中整數最大為N^7,表示為N進位制最大7位),因此N個數的轉化是O(n),而進行排序最多為7趟,每趟為O(n),因此演算法總複雜度約為O(7*N)。
具體程式碼如下:
public class BaseSort { // 排序N個比N^7小的數,要求的演算法是O(n) public static void sort(String[] strings) { if (strings.length <= 1) { return; } int n = strings.length; Vector<List<int[]>> vector = new Vector<List<int[]>>(); // 構建n個桶 for (int i = 0; i < n; i++) { vector.add(new ArrayList<int[]>()); } // 將輸入字串轉換為N進位制整數 Vector<int[]> results = StringTen2IntegerN(strings, n); int max = 0; for (int j = 0; j < n; j++) { if (max < results.get(j).length) { max = results.get(j).length; } } for (int i = 0; i < max; i++) { for (int j = 0; j < n; j++) { int[] integer = results.get(j); if (integer.length <= i) { vector.get(0).add(integer); } else { vector.get(integer[integer.length - i - 1]).add(integer); } } results.clear(); for (int j = 0; j < n; j++) { for (int j2 = 0; j2 < vector.get(j).size(); j2++) { results.add(vector.get(j).get(j2)); } vector.get(j).clear(); } } for (int i = 0; i < n; i++) { strings[i] = n2Ten(results.get(i), n); } } /** * 將字串陣列轉化為N進位制的整數陣列 */ private static Vector<int[]> StringTen2IntegerN(String[] strings, int n) { Vector<int[]> vector = new Vector<int[]>(); for (int i = 0; i < strings.length; i++) { vector.add(Ten2N(strings[i].toCharArray(), n)); } return vector; } /** * 將任意長度的十進位制字串轉換為n進位制的整數 * * @param csstrten * @param n * @return */ public static int[] Ten2N(char[] csstrten, int n) { int istdeclen = csstrten.length; // 儲存十進位制串的長度 int k = 1; // 儲存所有十進位制串數碼或運算的值,如果為0表示十進位制數碼串為0串 int quotient = 0; // 儲存餘數 int strten2NLen = 0; // N進位制串的長度 int i, j; // 迴圈下標 int[] strten2N = new int[100];//這裡的100其實在本程式中只需要7即可 int[] intdecten = new int[istdeclen]; for (i = 0; i < istdeclen; i++) { // 將十進位制串轉換為數字碼並存儲到臨時空間中去 intdecten[i] = csstrten[i] - '0'; } int tempsum = 0; for (i = 0; k != 0; i++) { // 結束條件為被除數為0 for (j = 0; j < istdeclen; j++) { k = 0; while (j < istdeclen) { // 把十進位制串前面的0過濾掉,不用每次都對十進位制串前面的0進行計算 k += intdecten[j]; if (k != 0) { k = 0; break; } j++; } if (j == istdeclen) { break; } tempsum = intdecten[j]; while (tempsum < n && j < istdeclen - 1) { intdecten[j] = 0; tempsum = tempsum * 10 + intdecten[++j]; } quotient = (tempsum % n); // 求數碼除以n的餘數,關鍵 intdecten[j] = tempsum / n; // 求數碼除以n的商,關鍵 if (j != istdeclen - 1) { // 如果j不是指向最後一位,那位將上一位的餘數乘以10加進下一個數去 intdecten[j + 1] = (intdecten[j + 1] + quotient * 10); } } k = 0; for (int tt = 0; tt < istdeclen; tt++) { if (intdecten[tt] != 0) { k = 1; break; } } strten2N[i] = quotient; // 除n取餘,把所得的餘數儲存起來,實際上儲存的是數字碼,關鍵 strten2NLen++; // N進位制串的長度加1 } int[] result = new int[strten2NLen]; for (int l = 0; l < strten2NLen; l++) { result[l] = strten2N[strten2NLen - l - 1]; } return result; } /** * 將n進位制的整數轉化為十進位制的字串 */ public static String n2Ten(int[] csstrN2ten, int n) { int istrtwo2tenlen = csstrN2ten.length; // 儲存n進位制串的長度 int istrtwo2tendeclen = 1; // 預設十進位制串的長度至少為1 int i, j; // 迴圈下標 int[] strtwo2tendec = new int[100]; // 該迴圈完成將n進位制數碼轉換為十進位制數碼的工作,每取一位n進位制數,對應的十進位制數要乘以n並加上所取的n進位制數 for (i = 0; i < istrtwo2tenlen; i++) { for (j = 0; j < istrtwo2tendeclen; j++) { strtwo2tendec[j] *= n; // 每一位十進位制數乘n } strtwo2tendec[0] += csstrN2ten[i]; // 十進位制數個位加上取得的十進位制數 for (j = 0; j < istrtwo2tendeclen || strtwo2tendec[j] >= 10; j++) { strtwo2tendec[j + 1] += strtwo2tendec[j] / 10; // 將每一位的前一位分離出十位,前把它加到該位來 strtwo2tendec[j] %= 10; // 該位被分離後,保留個位不變 } istrtwo2tendeclen = j + 1; // 如果進來的十進位制位使對應十進位制數長度增加1 } StringBuffer sBuffer = new StringBuffer(); for (int l = istrtwo2tendeclen - 1; l >= 0; l--) { sBuffer.append(strtwo2tendec[l]); } return sBuffer.toString(); } public static void main(String[] args) { String[] strings = new String[100000]; int max = (int) Math.pow(100000, 7); for (int i = 0; i < strings.length; i++) { int temp = new Random().nextInt(max); strings[i] = String.valueOf(temp); } // for (int i = 0; i < strings.length; i++) { // System.out.print(strings[i] + " "); // } // System.out.println(); System.out.println("開始排序!" + System.currentTimeMillis() / 1000); sort(strings); System.out.println("完成排序!" + System.currentTimeMillis() / 1000); // for (int i = 0; i < strings.length; i++) { // System.out.print(strings[i] + " "); // } } }