LeetCode之Weekly Contest 90
LeetCode第90場周賽記錄
第一題:親密字符串
問題:
給定兩個由小寫字母構(gòu)成的字符串?A?和?B?,只要我們可以通過交換?A?中的兩個字母得到與?B?相等的結(jié)果,就返回?true?;否則返回?false?。
示例 1:
輸入: A = "ab", B = "ba" 輸出: true示例 2:
輸入: A = "ab", B = "ab" 輸出: false示例 3:
輸入: A = "aa", B = "aa" 輸出: true示例 4:
輸入: A = "aaaaaaabc", B = "aaaaaaacb" 輸出: true示例 5:
輸入: A = "", B = "aa" 輸出: false鏈接:https://leetcode-cn.com/contest/weekly-contest-90/problems/buddy-strings/
分析:
1.如果兩個字符串長度不等,一定不滿足
2.如果兩個字符串完全相同,需要至少兩個完全相同的字符,才能滿足交換兩個字母后相同,所以如果長度小于2,也一定不滿足。
3.其他情況兩個字符串需要有且僅有兩個不同的字符,差異的兩個字符僅僅是順序不同。
?
AC Code:
1 class Solution { 2 public: 3 bool buddyStrings(string A, string B) { 4 if (A.size() != B.size() || A.size()<2) 5 { 6 return false; 7 } 8 //記錄不同的,如果兩者可以交換,返回true,完全相同,返回true 9 int counter = 0; //記錄差異點數(shù) 10 string A1=""; //分別保存差異內(nèi)容 11 string A2=""; 12 for (int i = 0; i < A.size(); i++) 13 { 14 if (A[i] != B[i]) 15 { 16 counter++; 17 A1 += A[i]; 18 A2 += B[i]; 19 } 20 } 21 if (counter == 0) 22 { 23 //完全一樣的兩個字符串 24 //需要有兩個完全一樣的字符 25 map<char, int> tmp; 26 for (int i = 0; i < A.size(); i++) 27 { 28 if (tmp.count(A[i])==1) 29 { 30 tmp[A[i]]++; 31 } 32 else 33 { 34 tmp[A[i]] = 1; 35 } 36 } 37 map<char, int>::iterator it; 38 for (it = tmp.begin(); it != tmp.end(); it++) 39 { 40 if (it->second >= 2) 41 { 42 return true; 43 } 44 } 45 return false; 46 } 47 if (A1.size()!=2) 48 { 49 return false; 50 } 51 else 52 { 53 if (A1[0] == A2[1] && A1[1] == A2[0]) 54 { 55 return true; 56 } 57 else 58 { 59 return false; 60 } 61 } 62 } 63 };其他:
第一的做法:
1 class Solution { 2 public boolean buddyStrings(String A, String B) { 3 int[] l = new int[256]; 4 boolean two = false; 5 for(int i = 0; i < A.length(); i++) { 6 if(++l[A.charAt(i)] > 1) two = true; 7 } 8 for(int i = 0; i < B.length(); i++) { 9 --l[B.charAt(i)]; 10 } 11 for(int out: l) { 12 if(out != 0) return false; 13 } 14 int error = 0; 15 for(int i = 0; i < A.length(); i++) { 16 if(A.charAt(i) != B.charAt(i)) { 17 error++; 18 } 19 } 20 if(error == 2) return true; 21 if(error > 2) return false; 22 return two; 23 } 24 }用的好像是Java,思路是先創(chuàng)建256大小字符數(shù)組【如果要對空間進(jìn)行優(yōu)化的話,可以只創(chuàng)建26個大小數(shù)組,因為題目中明確只有a-z,對應(yīng)做一個-‘a(chǎn)’處理即可,不過區(qū)別不大】,用來統(tǒng)計每個字母出現(xiàn)個數(shù),先統(tǒng)計A的數(shù)量,一旦有某個字符出現(xiàn)兩次及以上,將標(biāo)志two設(shè)為true。然后利用B中字符減去對應(yīng)個數(shù),結(jié)束后一旦某個字符對應(yīng)位置不是0,則說明A中和B中對應(yīng)字符個數(shù)不一致,一定不滿足要求,返回false,然后統(tǒng)計AB中差異個數(shù),如果差異個數(shù)是2,返回true,如果差異超過2,返回false,接下來一定是沒有差異(如果只有一個字符差異,一定不滿足AB中對應(yīng)字符個數(shù)一致要求,前面就會返回false),返回two的值,即是否有某個字符數(shù)量達(dá)到2.
?
第二題:括號的分?jǐn)?shù)
題目:
給定一個平衡括號字符串?S,按下述規(guī)則計算該字符串的分?jǐn)?shù):
- ()?得 1 分。
- AB?得?A + B?分,其中 A 和 B 是平衡括號字符串。
- (A)?得?2 * A?分,其中 A 是平衡括號字符串。
示例 1:
輸入: "()" 輸出: 1示例 2:
輸入: "(())" 輸出: 2示例?3:
輸入: "()()" 輸出: 2示例?4:
輸入: "(()(()))" 輸出: 6提示:
鏈接:https://leetcode-cn.com/contest/weekly-contest-90/problems/score-of-parentheses/
?
分析:
1.如果是(),值為1;
2.如果是“”,值為0;
3.對于某個string S,如果形如()S`,結(jié)果為1+value(S`)
如果形如(S`)S``,結(jié)果為2*value(S`)+value(S``)
已知給出字符串是平衡的,只需要按照規(guī)則遞歸分解求值即可
需要做的就是找出S`以及剩余字符串S``
AC code:
?
1 class Solution { 2 public: 3 int scoreOfParentheses(string S) { 4 if (S.size() == 0) //空串值為0 5 { 6 return 0; 7 } 8 if (S.size() == 2) //已知括號匹配,長度2的一定是(),值是1 9 { 10 return 1; 11 } 12 string tmp = ""; //嵌套的字符串 13 string left = ""; //當(dāng)前匹配后剩余的字符串 14 stack<char> tmpstack; //S[0]一定是'(' 15 if (S[1] == ')') // ()S`類型 16 { 17 for (int j = 2; j < S.size(); j++) 18 { 19 left += S[j]; 20 } 21 return 1 + scoreOfParentheses(left);; 22 } 23 tmp += S[1]; 24 tmpstack.push(S[1]); 25 for (int i = 2; i < S.size(); i++) 26 { 27 if (tmpstack.empty() == true && S[i] == ')') //完成匹配,形如(S`)S`` 28 { 29 for (int j = i + 1; j < S.size(); j++) 30 { 31 left += S[j]; 32 } 33 return 2 * scoreOfParentheses(tmp) + scoreOfParentheses(left); 34 } 35 else 36 { 37 tmp += S[i]; 38 if (tmpstack.empty() == true) 39 { 40 tmpstack.push(S[i]); 41 } 42 else if (tmpstack.top() == '(' && S[i] == ')') 43 { 44 tmpstack.pop(); 45 } 46 else 47 { 48 tmpstack.push(S[i]); 49 } 50 } 51 } 52 53 } 54 };其他:
第一的做法:
1 class Solution { 2 public int scoreOfParentheses(String S) { 3 if(S.length() == 0) return 0; 4 if(S.charAt(0) == '(' && S.charAt(1) == ')') { 5 return 1 + scoreOfParentheses(S.substring(2)); 6 } 7 int d = 0; 8 int end = -1; 9 for(int i = 0; i < S.length(); i++) { 10 if(S.charAt(i) == '(') d++; 11 else d--; 12 if(d == 0) { 13 end = i+1; 14 break; 15 } 16 } 17 return 2 * scoreOfParentheses(S.substring(1, end-1)) + scoreOfParentheses(S.substring(end)); 18 } 19 }基本思路基本一致,處理(S`)S``類型時候沒有使用棧而是直接通過識別‘('和')’加減計數(shù)來找到(S`)
?
第三題:鏡面反射
題目:
有一個特殊的正方形房間,每面墻上都有一面鏡子。除西南角以外,每個角落都放有一個接受器,編號為?0,?1,以及?2。
正方形房間的墻壁長度為?p,一束激光從西南角射出,首先會與東墻相遇,入射點到接收器?0?的距離為?q。
返回光線最先遇到的接收器的編號(保證光線最終會遇到一個接收器)。
?
示例:
輸入: p = 2, q = 1 輸出: 2 解釋: 這條光線在第一次被反射回左邊的墻時就遇到了接收器 2 。?
提示:
?
鏈接:https://leetcode-cn.com/contest/weekly-contest-90/problems/mirror-reflection/
?
分析:
1,利用鏡面反射特點,可以假設(shè)上面有無限長,光線一直向上走;
2,在1的前提下,每反射一次,向上高度增加q;
3,如果被某個接收器接收到了,說明當(dāng)前高度是p的整數(shù)倍;
4,如果反射偶數(shù)次被接收到,則必定是2號接收到;
5,如果最終達(dá)到的“高度”是墻面高度p的奇數(shù)倍,則被1號接收到;
6,如果最終達(dá)到的“高度”是墻面高度p的偶數(shù)倍,則被0號接收到;
分析完成后問題就變得很簡單了。
AC code:
1 class Solution { 2 public: 3 int mirrorReflection(int p, int q) { 4 //無限向上延伸,虛擬節(jié)點,整數(shù)倍獲得結(jié)果 5 int counter = 1; 6 while (true) 7 { 8 if (q*counter % p == 0) 9 { 10 if (counter % 2 == 0) 11 { 12 return 2; 13 } 14 if (q*counter / p % 2 == 0) 15 { 16 return 0; 17 } 18 return 1; 19 } 20 counter++; 21 } 22 } 23 };其他:
第一code
1 class Solution { 2 public int mirrorReflection(int p, int q) { 3 int curr = 0; 4 for(int i = 1; true; i++) { 5 curr += q; 6 curr %= (2*p); 7 if(curr == p) { 8 if(i%2 == 1) { 9 return 1; 10 } 11 else { 12 return 2; 13 } 14 } 15 if(curr == 0) { 16 return 0; 17 } 18 } 19 } 20 }假設(shè)房間向上翻轉(zhuǎn)一次,得到一個p寬,2*p高的長方形,curr記錄當(dāng)前高度(高度范圍[0,2*p)),每次反射高度增加q,如果高度等于0,則會被0號接受,如果高度等于p,則被1或者2接收,其中反射奇數(shù)次被1號接收,反射偶數(shù)次被2號接收。
感覺自己的code有一點不好的就是如果pq很大且數(shù)據(jù)巧合有可能溢出,映射到2p范圍內(nèi)會更好。
?
第四題:雇傭 K 名工人的最低成本
題目:
- 用戶通過次數(shù)0
- 用戶嘗試次數(shù)0
- 通過次數(shù)0
- 提交次數(shù)0
- 題目難度Hard
有?N?名工人。?第?i?名工人的工作質(zhì)量為?quality[i]?,其最低期望工資為?wage[i]?。
現(xiàn)在我們想雇傭?K?名工人組成一個工資組。在雇傭?一組 K 名工人時,我們必須按照下述規(guī)則向他們支付工資:
返回組成一個滿足上述條件的工資組至少需要多少錢。
示例 1:
輸入: quality = [10,20,5], wage = [70,50,30], K = 2 輸出: 105.00000示例 2:
輸入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3 輸出: 30.66667提示:
鏈接:https://leetcode-cn.com/contest/weekly-contest-90/problems/minimum-cost-to-hire-k-workers/
?
分析:
速度有點慢,最后20分鐘開始處理,沒想太多,測試數(shù)據(jù)到第41個超時了,O(n*n)毫無前途。
TimeOut COde:
1 class Solution { 2 public: 3 double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) { 4 double min = 9999999.0; 5 for (int i = 0; i < quality.size(); i++) 6 { 7 vector<double> tmpmin; 8 double tmp = wage[i]*1.0 / quality[i]; 9 for (int j = 0; j < quality.size(); j++) 10 { 11 if (quality[j] * tmp < wage[j]) 12 { 13 continue; 14 } 15 else 16 { 17 tmpmin.push_back(quality[j] * tmp); 18 } 19 } 20 if (tmpmin.size() < K) 21 { 22 continue; 23 } 24 else 25 { 26 sort(tmpmin.begin(), tmpmin.end()); 27 double tmpsum = 0; 28 for (int index = 0; index < K; index++) 29 { 30 tmpsum += tmpmin[index]; 31 } 32 if (tmpsum < min) 33 { 34 min = tmpsum; 35 } 36 } 37 } 38 return min; 39 } 40 };之前想法是算出每個人的“性價比”,即最低要求和工作質(zhì)量的比值,然后按照該比值衡量所有人,如果該比值下的工資低于最低期望,則不會加入,然后在加入里面選出最低的K個,得到一個總和,按照每個人的標(biāo)準(zhǔn)衡量一遍,所有總和中最低的一個即為符合要求的結(jié)果。但是顯然O(n*n)效率太低。
比賽到時見后參考別人code,發(fā)現(xiàn)按照性價比排序后只需要過一遍就能得到結(jié)果。
AC 思路:
單位工作質(zhì)量所要工資其實和性價比相反,越低越好。但是并不是說比值越低總價就越低,比如一個工作質(zhì)量/最低工資分別是[1,10]和[20,40],前者比值10,后者比值2,但是只要1個人的話顯然需要選擇前者。
按照wget/quality進(jìn)行升序排序,則只需要獲得quality總和即可,因為所采用的單位質(zhì)量價值都是相同的,都采用的最低的一個。由于采用的單位質(zhì)量價值相同,影響最終結(jié)果的只有quality值了,則每次需要將前k個中quality最大的一個移除進(jìn)行后面的嘗試。
在給出的第一組測試數(shù)據(jù)中,
[10,20,5]
[70,50,30]
計算wget/quality以及排序后結(jié)果如下:
[20,5.10]
[50,30,40]
[2.5,,6,7]
從中選擇2個,則第一次嘗試結(jié)果選擇前兩個,按照6計算,值為(20+5)*6=150
前面有分析過并非wget/quality低的總和就會少,所以需要進(jìn)行遍歷嘗試后面的所有值,
當(dāng)選擇下一個時候,由于確定比例會選擇7,影響到結(jié)果的只有quality值了,20>5,移除20,得到新的組合(5+10)*7=105
對于第二組測試數(shù)據(jù),按照同樣方式處理排序后結(jié)果如下
[10,10,3,1,1]
[2,2,4,7,8]
[0.2,0.2,1.3333,7,8]
選擇3個,第一次前三個組合得到(10+10+3)*1.333=30.6667
接下來嘗試比例7的,移除前面quality最大的10,(10+3+1)*7=98
嘗試比例8 ,移除quality最大的10,(3+1+1)*8=40,則最小值30.6667
?
AC code:
1 class Solution { 2 public: 3 typedef struct Worker 4 { 5 int quality; 6 int wage; 7 double ratio; 8 bool operator< (const Worker &w1) 9 { 10 return ratio < w1.ratio; 11 } 12 }Worker; 13 14 double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int K) 15 { 16 vector < Worker > workers; 17 for (int i = 0; i < quality.size(); i++) 18 { 19 Worker w = { quality[i], wage[i], wage[i] * 1.0 / quality[i] }; 20 workers.push_back(w); 21 } 22 //按照性價比排序 23 sort(workers.begin(), workers.end()); 24 double ret = INT_MAX; 25 vector<int> tmpqs;//由于性價比是下降的(wget/qualite 上升),即單位質(zhì)量花費是增加的,所以每次都把前面qualities最大的除去 26 for (int i = 0; i < workers.size(); i++) 27 { 28 if (tmpqs.size() < K) 29 { 30 tmpqs.push_back(workers[i].quality); 31 } 32 if (tmpqs.size() == K) 33 { 34 //得到一個組合,判斷是否更小 35 int tmpsumquality=0; 36 int tmpmaxindex = 0; 37 int tmpmaxquality = INT_MIN; 38 for (int j = 0; j < K; j++) 39 { 40 tmpsumquality += tmpqs[j]; 41 if (tmpqs[j]>tmpmaxquality) 42 { 43 tmpmaxindex = j; 44 tmpmaxquality = tmpqs[j]; 45 } 46 } 47 ret = min(ret, tmpsumquality*workers[i].ratio); 48 //然后需要移除當(dāng)前最大qualities 49 tmpqs.erase(tmpqs.begin() + tmpmaxindex); 50 } 51 } 52 return ret; 53 } 54 55 56 };其他:
1.DBL_MAX默認(rèn)是不認(rèn)的,所以應(yīng)改為INT_MAX
2.第一code
1 class Solution { 2 public double mincostToHireWorkers(int[] quality, int[] wage, int K) { 3 State[] l = new State[quality.length]; 4 for(int i = 0; i < quality.length; i++) { 5 l[i] = new State(quality[i], wage[i]); 6 } 7 Arrays.sort(l); 8 double ret = Double.MAX_VALUE; 9 PriorityQueue<Integer> q = new PriorityQueue<Integer>(); 10 long sum = 0; 11 for(int i = 0; i < l.length; i++) { 12 q.add(-l[i].quality); 13 sum += l[i].quality; 14 if(q.size() > K) { 15 sum += q.poll(); 16 } 17 if(q.size() == K) { 18 ret = Math.min(ret, sum * l[i].ratio()); 19 } 20 } 21 return ret; 22 } 23 class State implements Comparable<State> { 24 public int quality; 25 public int wage; 26 public State(int quality, int wage) { 27 super(); 28 this.quality = quality; 29 this.wage = wage; 30 } 31 public double ratio() { 32 return wage / (double) quality; 33 } 34 public int compareTo(State s) { 35 return Double.compare(ratio(), s.ratio()); 36 } 37 @Override 38 public String toString() { 39 return "State [quality=" + quality + ", wage=" + wage + "]"; 40 } 41 42 } 43 } a.利用了PriorityQueue自動調(diào)整結(jié)構(gòu)的特定,通過poll將最大quality移除掉b.通過*-1將最小堆轉(zhuǎn)換為最大堆
c. 1 for(int i = 0; i < l.length; i++) { 2 q.add(-l[i].quality); 3 sum += l[i].quality; 4 if(q.size() > K) { 5 sum += q.poll(); 6 } 7 if(q.size() == K) { 8 ret = Math.min(ret, sum * l[i].ratio()); 9 } 10 }
中,q.poll的有可能就是剛插入進(jìn)去的,比如某個quality最大,同時ratio也比較大的,完全可以直接跳過,也許能夠進(jìn)一步優(yōu)化,不過這樣做的好處就是形式的統(tǒng)一。
?
總結(jié):
第四次參加周賽了,雖說仍然沒能完成四道題,不過至少四個都懂了,也算是有所收獲。和高手比起來,感覺最欠缺的一是速度,二是對語言特性的掌握,三是對常用算法的掌握。
1.速度上來講第一四道題做完不到20分鐘,自己第一個AC都快18分鐘了,即使會做沒時間做也是白搭,即使是實際項目中,也是越早做出來越早發(fā)現(xiàn)問題有時間完善改進(jìn)。
2.雖說C/C++/C#/Java/Go/Python/Swift/Kotlin/VB等都稍有涉獵,能拿來用,尤其C/C++從開始于到現(xiàn)在都六七年了,不過僅僅限于基礎(chǔ)用法的使用,好多高階用法并沒掌握,所以一旦需要要么臨時搜索查詢,要么根本就不知道有只能笨拙的自己實現(xiàn),掌握多門語言固然不錯,但是要有自己的核心技能語言,暫且選擇C++/C#好了,今后不僅要能用,更要用好,要深入理解掌握。
3.見多方能識廣,承認(rèn)有天才,但自認(rèn)為不是,而大多數(shù)問題其實都已經(jīng)存在且被解決,一方面固然需要提高自己的獨立思考能力,另一方面也不能閉門造車,多學(xué)習(xí)其他人,才能更快的提高。
化用老師的一句話:大量練習(xí),大量做題,大量閱讀,自然能夠提高。
practice makes prefect
轉(zhuǎn)載于:https://www.cnblogs.com/youdias/p/9220748.html
總結(jié)
以上是生活随笔為你收集整理的LeetCode之Weekly Contest 90的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html5-6 Frame框架窗口类型
- 下一篇: OpenGL 笔记1 固定管线实例 +