設計模式
命令模式
本來可以將命令作爲一個抽象類,每個命令寫成一個具體類,然後客戶端直接調用具體命令類。
對於命令模式,大家可能 心存疑慮,明明是一個很簡單的調用邏輯,爲什麼要做如此的複雜,爲什麼不直接reciver的excute方法就可以實現功能?調用邏輯複雜,是爲了如果後續命令的增加, 能夠應對後續需求的變化。簡單的只是開發起來方便,但對後續的維護則是困難。除此之外,使用命令模式的另一個好處是可以實現命令記錄的功能,可以在調用者裏面使用一個數據結構來存儲執行過的命令對象,以此可以方便地知道剛剛執行過哪些命令,並可以在需要是恢復。並且可以在調用者中執行日誌的記錄。
命令模式
也就是說,invoker類是具體的執行者,command類是封裝命令,其中數據成員有invoker對象,receiver類是接收者類,client對象直接發送命令給receiver,這樣就把請求和具體實現分開了,而且最重要一點是,可以在receiver對象中,創建一個容器對象存儲命令,可以實現命令撤銷和重做。
職責鏈模式
當一個請求發出時,低級處理者級別不夠,處理不了,就會把這個請求發給更高一級,所以這個請求就像在職責鏈上傳遞,直到有一個對象處理它。
Handler類:抽象處理類,包含自己類的對象,代表比此對象高一級對象
Concreate類:具體處理者類。可訪問它的後繼者,如果可以處理就處理,不能處理,就發給後繼者。
缺點:如果處理不當,請求會一直沒人處理,陷入死循環
中介者模式
中介者模式
當同事類之間存在相互影響的時候,也就是說,A類對象改變,B類對象也會改變,這時候用中介類來降低耦合。
享元模式
訪問者模式
ToDo
算法
N皇后問題
輸出有多少可能組合。
bool isvalid(vector<int>& mat,int i,int j) {
for(int k = 0; k < i;k++) {
if (mat[k] == j || abs(i-k) == abs(j - mat[k]))
return false;
}
return true;
}
int dfs(vector<int> mat,int i,int n) {
int res = 0;
if (i == n) {
return 1;
}
for (int j = 0; j < n; j++) {
if (isvalid(mat,i,j)) {
mat[i] = j;
res += dfs(mat,i+1,n);
// mat[i] = -1;
}
}
return res;
}
判斷兩個字符串是否爲變形詞
兩個字符串,s1,s2,如果兩個字符串包含的字符一樣,但是順序可能不一樣,就說這兩個是變形詞。
方法1:1.先判斷兩個字符串長度是否相同 2. 遍歷字符串,用數組保存每個字符出現的次數。 3.比較兩個數組每個Index的數值是否相同,出現相同的話就說明不是變形詞。
bool helper(string s1,string s2) {
int m = s1.size(),n = s2.size();
if (m != n)
return false;
vector<int> map1(128,0),map2(128,0);
for (auto ch : s1) {
map1[ch]++;
}
for (auto ch : s2)
map2[ch]++;
for (int i = 0; i < 128; i++) {
if (map1[i] != map2[i])
return false;
}
return true;
}
方法2:第一種方法,建立了兩個數組,其實只需要一個數組,記錄str1中的字符出現頻次,然後遍歷str2,當出現字符ch,map[ch]-1就可以,當出現<0的情況,返回false;
bool helper(string s1,string s2) {
int m = s1.size(),n = s2.size();
if (m != n)
return false;
vector<int> map1(128,0);
for (auto ch : s1) {
map1[ch]++;
}
for (int i = 0; i < s2.size(); i++) {
map1[s2[i]]--;//主要是這裏變化
if (map1[s2[i]] < 0)//判斷是否小於0
return false;
}
return true;
}
字符串中數字子串的和
給定一個字符串,包括數字,字母,各種符號,當出現’-‘號時,看連續’-‘個數,奇數個數代表是負數,偶數個數代表正數,比如說,“A-1BC–12",那麼包含數字-1和12.
方法1:遍歷字符串,用一個flag標誌符號,當出現’-‘,就連續判斷之後的字符還是否爲’-’;當出現數字時,連續判斷之後出現的是否爲數字。當數字開始前的符號爲’-‘纔會用flag標誌。
int helper(string s) {
int res = 0;
int n = s.size();
bool flag = true;
for (int i = 0; i < n; i++) {
if (s[i] >= '0' && s[i] <= '9') {
if (i > 0 && s[i-1] != '-')
flag = true;
string temp = "";
while ((i < n) && (s[i] >= '0' && s[i] <= '9')) {
temp += s[i];
i++;
}
i--;
int t = stoi(temp);
res += flag ? t : -t;
flag = true;
}
if (s[i] == '-') {
while ((i < n) && (s[i] == '-')) {
flag = !flag;
i++;
}
i--;
}
}
return res;
}
方法2:從左導向右遍歷字符,準確收集數字,然後相加。關鍵點是怎麼把連續的數字組成一個數的過程,比起來上一個方法stoi好很多。
TODO
去掉字符串中連續出現k個’0‘的子串
字符串中會出現k個’0‘,去掉後,返回去掉後的字符串,比如”120000300“,k= 2,則處理後結果爲”1200003“。
方法1:
string helper(string s,int k) {
int pos = 0,num = 0;
int n = s.size();
for (int i = 0; i < n; i++) {
if (s[i] == '0') {
num++;
}
else {
if (num == k) {
pos = pos - 2;
}
num = 0;
}
s[pos++] = s[i];
}
if (num == 2)
pos = pos - 2;
return s.substr(0,pos);
}
判斷兩個字符串是否爲旋轉字符串
s1 = “12345”,那麼s1的旋轉字符串有”23451“,”34512“,”45123“,”51234“,”12345“。所以給定兩個字符串s1,s2,判斷是不是互爲旋轉字符串。
方法1:把s2從第一個字符開始,每一個字符都放到最後一位,判斷兩個字符串是否相同。
bool isSame(string s1,string s2) {
int m = s1.size(),n = s2.size();
if (m != n)
return false;
string temp = s2;
for (int i = 0; i < n; i++) {
if (temp == s1)
return true;
temp = temp.substr(1,n-1) + temp[0];
}
return false;
}
方法2:另str= str2 + str2,然後判斷str中是否包含子串str1,因爲str包含所有旋轉子串。