1. 動態連接庫和靜態連接庫的優缺點php
2. 輪詢任務調度和可搶佔式調度有什麼區別?web
3. 列出數據庫中經常使用的鎖及其應用場景算法
1. 給定N是一個正整數,求比N大的最小「不重複數」,這裏的不重複是指沒有兩個相等的相鄰位,如1102中的11是相等的兩個相鄰位故不是不重複數,而12301是不重複數。數據庫
2. 設N是一個大整數,求長度爲N的字符串的最長迴文子串。編程
3. 座標軸上從左到右依次的點爲a[0]、a[1]、a[2]……a[n-1],設一根木棒的長度爲L,求L最多能覆蓋座標軸的幾個點?數組
1. 在現代系統的設計過程當中,爲了減輕請求的壓力,一般採用緩存技術,爲了進一步提高緩存的命中率,同常採用分佈是緩存方案。調度模塊針對不一樣內容的用戶請求分配給不一樣的緩存服務器向用戶提供服務。請給出一個分佈式緩存方案,知足以下要求:緩存
1) 單臺緩存服務器故障,整個分佈式緩存集羣,能夠繼續提供服務。服務器
2)經過必定得分配策略,能夠保證充分利用每一個緩存服務的存儲空間,及負載均衡。當部分服務器故障或系統擴容時,改分配策略能夠保證較小的緩存文件重分配開銷。網絡
3)當不一樣緩存服務器的存儲空間存在差別時,分配策略能夠知足比例分配。併發
a. 共享:多個應用程序可使用同一個動態庫,啓動多個應用程序的時候,只須要將動態庫加載到內存一次便可;
b. 開發模塊好:要求設計者對功能劃分的比較好。
缺點是不能解決引用計數等問題。
(2)靜態庫(Static Library):函數和數據被編譯進一個二進制文件(一般擴展名爲.LIB)。在使用靜態庫的狀況下,在編譯連接可執行文件時,連接器從庫中複製這些函數和數據並把它們和應用程序的其它模塊組合起來建立最終的可執行文件(.EXE文件)。靜態連接庫做爲代碼的一部分,在編譯時被連接。優缺點以下:
代碼的裝載速度快,由於編譯時它只會把你須要的那部分連接進去,應用程序相對比較大。可是若是多個應用程序使用的話,會被裝載屢次,浪費內存。
// 求比指定數大且最小的「不重複數」 #include <stdio.h> void minNotRep(int n) { // 須要屢次判斷 while(1) { int a[20], len = 0, i, b = 0; // flag爲true表示是「重複數」,爲false表示表示是「不重複數」 bool flag = false; // 將n的各位上數字存到數組a中 while(n) { a[len++] = n % 10; n = n / 10; } // 從高位開始遍歷是否有重複位 for(i = len - 1; i > 0; i--) { // 有重複位則次高位加1(最高位有可能進位但這裏不須要額外處理) if(a[i] == a[i - 1] && !flag) { a[i - 1]++; flag = true; } else if(flag) { // 將重複位後面的位置爲0101...形式 a[i - 1] = b; b = (b == 0) ? 1 : 0; } } // 重組各位數字爲n,若是是「不重複數」則輸出退出不然繼續判斷 for(i = len - 1; i >= 0; i--) { n = n * 10 + a[i]; } if(!flag) { printf("%d\n", n); break; } } } int main() { int N; while(scanf("%d", &N)) { minNotRep(N + 1); } return 0; }
當i==j時,P[i][j]=true
當i+1==j時,P[i][j]=str[i]==str[j]
其餘,P[i][j]=P[i+1][j-1]&&(str[i]==str[j])
那麼P[i][j]中j-i+1最大的且值爲true的就是最長迴文子串。這樣,這個方法的時間複雜度爲O(n^2),空間複雜度爲O(n^2)。比暴力法有很大的改進。
Source Code:
#include <stdio.h> #include <stdlib.h> #include <string.h> int longestPalSubstr(char *str) { int n = strlen(str); int i, j, len, maxlen = 0, maxi = 0, maxj = 0; bool **P = (bool**)malloc(sizeof(bool) * n); for(i = 0; i < n; i++) { P[i] = (bool*)malloc(sizeof(bool) * n); } // initialize P[i][i] for(i = 0; i < n; i++) { P[i][i] = true; } // compute P[n][n] by length for(len = 2; len <= n; len++) { for(i = 0; i < n - len + 1; i++) { j = i + len - 1; if(len == 2) { P[i][j] = (str[i] == str[j]); } else { P[i][j] = ((str[i] == str[j]) && P[i + 1][j - 1]); } } } // int k; for(i = 0; i < n; i++) { for(j = i; j < n; j++) { // printf("%d ", P[i][j]); if(P[i][j] && maxlen < (j - i + 1)) { maxlen = j - i + 1; maxi = i; maxj = j; } } // printf("\n"); // for(k = 0; k <= i; k++) // printf(" "); } printf("The longest palin substr is "); for(i = maxi; i <= maxj; i++) { printf("%c", str[i]); } printf(", maxlen is %d\n\n", maxlen); return maxlen; } int main() { char str[100]; while(1) { gets(str); if(strlen(str) == 0) break; longestPalSubstr(str); } return 0; }
算法3:第三個方法,能夠從上面那個方法的狀態轉移方程得到啓發,對於每個迴文子串能夠先肯定一箇中心,而後向兩邊擴展,這樣能夠在時間複雜度O(n^2),空間複雜度O(1)的狀況下完成,須要注意的是,長度爲奇數和偶數的中心的狀況是不一樣的。
Source Code:
#include <stdio.h> #include <stdlib.h> #include <string.h> int longestPalSubstr(char *str) { int len = strlen(str); int i, maxLen = 1, start = 0; int low, high; // 將每一個字符做爲中心向兩邊擴展判斷 for(i = 1; i < len; i++) { // 處理長度爲偶數的狀況 low = i - 1; high = i; while(low >= 0 && high < len && str[low] == str[high]) { if(maxLen < high - low + 1) { start = low; maxLen = high - low + 1; } low--; high++; } // 處理長度爲奇數的狀況 low = i - 1; high = i + 1; while(low >= 0 && high < len && str[low] == str[high]) { if(maxLen < high - low + 1) { start = low; maxLen = high - low + 1; } low--; high++; } } printf("The longest palin substr is "); for(i = start; i < start + maxLen; i++) { printf("%c", str[i]); } printf(", maxlen is %d\n\n", maxLen); return maxLen; } int main() { char str[100]; while(1) { gets(str); if(strlen(str) == 0) break; longestPalSubstr(str); } return 0; }
算法4:第四個方法採用後綴數組,將最長迴文子串的問題轉化爲最長公共前綴的問題。具體的作法就是:將整個字符串翻轉以後,拼接到原字符串後,注意用特殊字 符分開,這樣問題就變成了新的字符串的某兩個後綴的最長公共前綴的問題了。這個方法比較強大,不少字符串的問題都可以巧妙的解決。不過實現起來也相對比較:難,好的實現和差的實現時間複雜度相差很大。因爲對後綴數組不是很清楚,未寫代碼,等學習了後綴數組再過來補。
算法5:第五個方法叫作Manacher算法,是一種線性時間的方法,很是巧妙。首先,咱們在上面的方法中個,都要考慮迴文長度爲奇數或者偶數的狀況。這個:方法,引入一個技巧,使得奇數和偶數的狀況統一處理了。具體作法以下:
abba轉換爲#a#b#b#a#,也就是在每個字符兩邊都加上一個特殊字符。
而後建立一個新的P[i]表示,以第i個字符爲中心的迴文字串的半徑。例如上面的例子,對應的P以下,設S爲原始字符串:
S | # | a | # | b | # | b | # | a | # |
P | 1 | 2 | 1 | 2 | 5 | 2 | 1 | 2 | 1 |
經過觀察上面的表,你們能夠發現P[i]-1就是實際迴文字串的長度。若是知道P,遍歷一次就知道最長的迴文子串。能夠該如何計算P呢?這是這個算法最核心的部分。
下面的討論基本轉自博客:http://www.felix021.com/blog/read.php?2040 該博客中對Manacher算法介紹得也很是好,向你們推薦。
算法引入兩個變量id和mx,id表示最長迴文子串的中心位置,mx表示最長迴文字串的邊界位置,即:mx=id+P[id]。
在這裏有一個很是有用並且神奇的結論:若是mx > i,那麼P[i] >= MIN(P[2 * id - i], mx - i) 分開理解就是:
若是mx - i > P[j], 則P[i]=P[j]
不然,P[i] = mx - i.
這兩個該如何理解呢?具體的解釋請看下面的兩個圖。
(1)當 mx - i > P[j] 的時候,以S[j]爲中心的迴文子串包含在以S[id]爲中心的迴文子串中,因爲 i 和 j 對稱,以S[i]爲中心的迴文子串必然包含在以S[id]爲中心的迴文子串中,因此必有 P[i] = P[j],見下圖。
(2)當 P[j] >= mx - i 的時候,以S[j]爲中心的迴文子串不必定徹底包含於以S[id]爲中心的迴文子串中,可是基於對稱性可知,下圖中兩個綠框所包圍的部分是相同的,也就是 說以S[i]爲中心的迴文子串,其向右至少會擴張到mx的位置,也就是說 P[i] >= mx - i。至於mx以後的部分是否對稱,就只能老老實實去匹配了。
對於 mx <= i 的狀況,沒法對 P[i]作更多的假設,只能P[i] = 1,而後再去匹配了。
理解了上面的一點,就沒有問題了。
Source Code:
#include <stdio.h> #include <stdlib.h> #include <string.h> int longestPalSubstr(char *str) { char s[100]; int i, maxLen = 1, start = 0, j; int len = strlen(str); int mx = 0, id = 0, min; s[0] = '$'; s[1] = '#'; for(i = 0, j = 2; i < len; i++, j += 2) { s[j] = str[i]; s[j + 1] = '#'; } s[j] = '\0'; len = len * 2 + 1; int *p = (int *)malloc(sizeof(int) * len); memset(p, 0, len); p[0] = 1; for(i = 1; i < len; i++) { min = p[2 * id - i] > (mx - i) ? (mx - i) : p[2 * id - i]; p[i] = mx > i ? min : 1; while(s[i + p[i]] == s[i - p[i]]) { p[i]++; } if(i + p[i] > mx) { mx = i + p[i]; id = i; } } for(i = 0; i < len; i++) { //printf("%d ", p[i]); if(maxLen < p[i] - 1) { maxLen = p[i] - 1; start = i - maxLen; } } printf("The longest palin substr is "); for(i = start; i < start + 2 * maxLen + 1; i++) { if(s[i] != '#') { printf("%c", s[i]); } } printf(", maxlen is %d\n\n", maxLen); return maxLen; } int main() { char str[100]; while(1) { gets(str); if(strlen(str) == 0) break; longestPalSubstr(str); } return 0; }
有兩點須要注意:
// 求最大覆蓋點 #include <stdio.h> int maxCover(int a[], int n, int L) { int count = 2, maxCount = 1, start; int i = 0, j = 1; while(i < n && j < n) { while((j < n) && (a[j] - a[i] <= L)) { j++; count++; } // 退回到知足條件的j j--; count--; if(maxCount < count) { start = i; maxCount = count; } i++; j++; } printf("covered point: "); for(i = start; i < start + maxCount; i++) { printf("%d ", a[i]); } printf("\n"); return maxCount; } int main() { // test int a[] = {1, 3, 7, 8, 10, 11, 12, 13, 15, 16, 17, 18, 21}; printf("max count: %d\n\n", maxCover(a, 13, 8)); int b[] = {1,2,3,4,5,100,1000}; printf("max count: %d\n", maxCover(b, 7, 8)); return 0; }