leetcode_OJ WC76 解題心得
- Contest time: Mar 18, 2018
PA. 800. Similar RGB Color 麻煩的水題
如題目所述,會需要用到一些位元運算,因此稍嫌麻煩,居然寫了一個多小時才寫出來。 中途還被變更的題說明耍了一道,而且題目說明根本說錯了gg。
cti itc 可以在十六進位和char互相轉換,頗為方便。而stringstream可以把字串在視為輸入處理一次轉成十六盡位在輸入給整數。
#define FORI(n) for(int i = 0; i < n; ++ i) #include <cstdlib> class Solution { public: int cti(char c) { if ( '0'<=c && c<='9' ) return c-'0'; else return 10+c-'a'; } char itc(int i) { if (0<=i && i<=9) return '0'+i; else return 'a'+i-10; } string similarRGB(string color) { int dist = 0, best = 99999999; int original = 0; color = color.substr(1,6); stringstream ss; ss<<hex<<color; ss>>original; int R,G,B,nr,ng,nb,nr1,ng1,nb1; string sr,sg,sb; R=original & 0xff0000; G=original & 0xff00; B=original & 0xff; R>>=16; G>>=8; //find smallest R for(int i = 0;i < 16;i++) { nr = i<<4 | i; if(abs(nr-R)<best) { sr=""; best = abs(nr-R); nr = i; sr += itc(i); } } //fins smallest G best = 99999999; for(int i = 0;i < 16;i++) { ng = i<<4 | i; if(abs(ng-G)<best) { sg=""; best = abs(ng-G); ng = i; sg += itc(i); } } //find smallest B best = 99999999; for(int i = 0;i < 16;i++) { nb = i<<4 | i; if(abs(nb-B)<best) { sb=""; best = abs(nb-B); nb = i; sb += itc(i); } } return "#"+sr+sr+sg+sg+sb+sb; } };
PB.801. Minimum Swaps To Make Sequences Increasing 動態規劃
從題目的性質可以看出,每一個階段均要不斷求解這個階段是否要交換(重疊子問題),以符合嚴格遞增的序列。
但是在每一個遞增中,如果每一個元素和它前一個元素都符合嚴格增(最優子結構),那麼整個數列也會是一個嚴格增。
此外,如果本來就符合嚴格增,就不用擔心,或是因為之前的交換(至i-1)而導致第i個需要替換,便需要檢查此次是否要換,也就是向前檢查到前一個。
因此既有符合重疊子問題,又有最優子結構,那就是動態規劃試用的範圍囉
參考連結:什麼時候用動態規劃演算法
出題者解析
解析的翻譯翔見程式碼中的註解
#define FORI(n) for(int i = 0; i < n; ++ i) class Solution { public: int minSwap(vector<int>& A, vector<int>& B) { int sz = A.size(); vector<int> swap(sz, INT_MAX),unswap(sz, INT_MAX); //calculating the step of swapped or not till this place. unswap[0] = 0; swap[0] = 1; for(int i = 1;i < sz;i++) { //如果兩方都依然符合遞增,則可以一次換兩個column或是都不要換,因為之前的已經符合嚴格遞增 if(A[i - 1] < A[i] && B[i - 1] < B[i]) //推理過來必定也會繼續嚴格遞增,否則就會被替換了 { unswap[i] = min(unswap[i - 1], unswap[i]); //如果不要替換,就是依然維持跟上一次一樣的未替換數字(這一次是intmax 所以一定會取到較小的) swap[i] = min(swap[i - 1] + 1, swap[i]); //如果要替換,那麼先前累積的替換次數到這裡就會再多一次,因為現在多的i又要再換一次了。 } //若是這種交叉符合形,則i或是i-1位置可以有一個必要被替換,也就是i, i-1會有遞增形成。(這種意思就是說,因為A B的『雙重符合』遞增在此被打斷了』 //因為被打斷,勢必得利用交換其中一個,例如將i or i-1 其中之一各自替換即可。 if(A[i - 1] < B[i] && B[i - 1] < A[i]) { unswap[i] = min(unswap[i], swap[i - 1]); //如果不要替換這一個,依然能讓整個數列嚴格增,那麼先前的勢必都要符合嚴格遞增的形式,因此得替換上一個 //也就是討論串裡面所說的:the cost n2 of having a legal sequence up to column i that ends with column i not flipped, is going //to be the cost s1 of having a legal sequence up to column i-1 that ends in column i-1 flipped swap[i] = min(unswap[i - 1] + 1, swap[i]); //如果要替換這一個,才能讓整個數列嚴格增,那就代表先前到i-1都要是持續嚴格增,因此從這裡開始替換就是算先前沒替換但這個有替換,所以是從unswap + 1 } } return min(swap[sz - 1], unswap[sz - 1]); } };
PC. 802. Find Eventual Safe States 圖論經典題,查找環以及可能觸及環之所有點
利用一個資料結構來儲存所有點的類型 -1代表尚未處理 0代表不在環上,或是不可能觸及到他人的環 1代表是環的一部分
優化只尋找還沒處理過得點,其他再把標記為0的點,放到結果裡面。
但依然優化不夠TLE:( 先放置吧
Wrong Answer 37/111 複雜的暴力作法,還會錯
TLE 81/111 提早跳出,但依然TLE
以下代碼優化到 101/111 但依然TLE了 先『精神』ac一下。
代碼邏輯見註解
#define FORI(n) for(int i = 0; i < n; ++ i) class Solution { public: vector<int> res, visited, in_cycle; vector<int> eventualSafeNodes(vector<vector<int>>& graph) { in_cycle.resize(graph.size()); fill(in_cycle.begin(), in_cycle.end(), -1); //-1 for unprocessed, 1 for in cycle and 0 for not in cycle FORI(graph.size()) { if(in_cycle[i] == -1) //if this node is not the terminal node { if(graph[i].size()) //the node which unsure in a node should be processed, otherwiswe, just dont do { visited.resize(graph.size()); fill(visited.begin(), visited.end(), 0); // cout<<"Start from "<<i<<endl; if(!dfs(i, i, graph, 0)) { in_cycle[i] = 0; } } else { in_cycle[i] = 0; } } } // cout<<" is in_cycle "; FORI(in_cycle.size()) { if(in_cycle[i] == 0) { res.push_back(i); } // cout<<in_cycle[i]<<" "; } return res; } bool dfs(int cur_node, int start, vector<vector<int>> graph,int step) { // cout<<" DFS to "<<cur_node<<endl; // cout<<" is in_cycle "; FORI(in_cycle.size()) { cout<<in_cycle[i]<<" "; } // cout<<endl; if(in_cycle[cur_node] == 1) { // cout<<"Hit a node that causes cycle "<<endl; return true; } else if(in_cycle[cur_node] == 0) //reach the node that will not form a cycle, which is safe { return false; } if(visited[cur_node] == 1) //visit the visited node again, that is a cycle { // cout<<"Hit a node that visited before, CYCLE CONFIRMED!! now cur_node is "<<cur_node<<endl; in_cycle[cur_node] = 1; return true; } //traversed_path.push_back(cur_node); visited[cur_node] = 1; FORI(graph[cur_node].size()) //search the next node that can be traversed from the current node { //if this node will connect to its neighbor that forms a circle, than cur_node will be treated as circle-hazard as well //cout<<i<<endl; if(dfs(graph[cur_node][i], start, graph, step + 1)) { in_cycle[cur_node] = 1; // cout<<"Node "<<cur_node<<" connect to "<<i<<" that forms a cycle "<<endl; return true; } } visited[cur_node] = 0; //if next traverse meet the terminal, it does not count as meet before that form a cycle since terminal is OK to meet again in_cycle[cur_node] = 0;//this node is terminal since the aforementioned FORI wont get in, so this is the node with output degree zero return false; } };