# [AIdrifter CS 浮生筆錄](https://hackmd.io/bKL1LVo8RaCKn02uHJW2BA) : BCR # Best conceivable Rutime 最理想執行時間 ## BCR: 一個問題能夠得到最好的執行時間 - 程式解題常常會遇到這問題,這演算法還有辦法在優化嗎?  - 教課書並不會特別提到BCR,但是分析解題非常有用,利用BCR(最佳理想執行時間),先思考input data和最後輸出的output data考慮其Time Complexity,再去思考最佳情況執行時間的Optimized algorithm,才不會迷失在問題內。 先個經典範例 ## 輸出兩陣列中交集元素的index Given two **sorted** arrays, find the number of elements in common. The arrays are the same length and each has all distinct elements. Let's start with a good example. We will underline those elements in common. ![](https://i.imgur.com/P8jSxvm.png) ## Optimzed Algorithms ### Brute Force :::info Brute Force : O(n^2) Optimzed Algo : ? BCR: O(2N) ::: - Brute Force: ```C++ vector<int> A = {13, 27, 35, 40, 49, 55, 59}; vector<int> B = {14, 35, 38, 40, 41, 50, 55}; vector<pair<int,int>> ans; for(size_t i=0;i<A.size();i++) for(size_t j=0;j<B.size();j++) if(A[i]==B[j]) ans.push_back({i,j}); ``` - 這邊思考,我們最後輸出paris,最起碼兩個陣列的元素都要access到,所以時間複雜度是O(A+B)=>O(2N)=>O(N) - 所以最後演算法時間複雜度會介在O(N^2)~O(N) 之間,我們可以開始思考有哪些演算法。 - 補充一下C++ pairs輸出方式 ```C++ for(auto p:ans) cout<<p.first<<" "<<p.second<<endl; for(auto [a,b]:ans) cout<<a<<" "<<b<<endl; ``` ### Binary Search :::info Brute Force : O(n^2) Optimzed Algo : - Binary Search : O (N log N) BCR: O(2N) ::: - 一定需要去travesal全部的A元素,再去找B,如果找B這一段改用binary Search呢? O(AB) => O(AlogB) => O(NlogN) ```C++ int binarySearch(int l,int r, vector<int> &A , int target){ while(1){ if(l==r) return -1; int mid = l + (r-l)/2; if(A[mid] == target) return mid; else if(A[mid] > target) r = mid; else l = mid + 1; } } int main(){ vector<int> A = {13, 27, 35, 40, 49, 55, 59}; vector<int> B = {14, 35, 38, 40, 41, 50, 55}; vector<pair<int,int>> ans; for(size_t i=0;i<A.size();i++){ int idx = binarySearch(0, B.size(),B ,A[i]); if(idx!=-1) ans.push_back({i,idx}); } } ``` ### Hash Table :::info Brute Force : O(n^2) Optimzed Algo : - Binary Search : O (N log N) - Hash Table : O(N) BCR: O(2N) ::: - 有辦法比O(logn)還要快嗎?,事實上用hash table先建表後,之後每次search B都是O(1),所以現在最快就是O(A)*O(1) => O(N),因為有BCR,我們知道我們不可能有時間複雜度更快的方法了,我們要**想辦法減少空間複雜度了**。 ```C++ vector<int> A = {13, 27, 35, 40, 49, 55, 59}; vector<int> B = {14, 35, 38, 40, 41, 50, 55}; vector<pair<int,int>> ans; unordered_map<int,int> T; for(size_t i=0; i<B.size(); i++) T[B[i]] = i; for(size_t i=0;i<A.size();i++){ if(T.find(A[i])!=T.end()) ans.push_back({i, T[A[i]]}); } ``` ### Two Pointer :::info Brute Force : O(n^2) Optimzed Algo : - Binary Search : O (N log N) - Hash Table : O(N) - Two Pointer: O(N), Space O(N) BCR: O(2N) ::: 先想想剛剛的Binary Search 1. Do a binary search in B for A[0] (13)- not found 2. Do a binary search in B for A[1] (27)- not found 3. Do a binary search in B for A[2] (35)- found at B[1] 4. Do a binary search in B for A[3] (40) - found at B[3] 5. Do a binary search in B for A[4] (49)- not found 我們用BUD檢查 - B: Bottle necks - 花費最多地方就是O(A)*O(1),traversal A所有元素,並找A元素元素有沒有在B的hash table內。已經是BCR,不能再快了。 - U: Unecessary - 發現Step 4 不需(Unecessary)用Binary Seach,因為35已經找到了,而45一定比35大,所以35在地B[1] 之前都不需要找。 - 這邊用到題目提示的性質 : Sorted Array - D: Duplicate - 沒發現重複的code。 利用Uncessary性質,我們改用Two pointer,節省了原本hash table所需要的空間,時間複雜度為BCR O(N),空間複雜度為O(1),我們已經無法再優化了!! ```C++ vector<int> A = {13, 27, 35, 40, 49, 55, 59}; vector<int> B = {14, 35, 38, 40, 41, 50, 55}; vector<pair<int,int>> ans; int j = 0; for(size_t i=0;i<A.size();i++){ while(A[i]>B[j]) j++; if(A[i]==B[j]) ans.push_back({i ,j}); } ``` ## Summary - 可用執行時間作為必須減少哪部分的提示 - 最快就是O(n),中間可以用哪方法從O(N^2)降到O(N)? 題目提示的sorted過的array就是關鍵。 - 小於或等於BCR的工作都是「免費」的,因不會影響執行時間: - 想將搜尋時間由O(log n)降至O(1),可以做「預先計算」,也就是將B陣列的元素全部建成Hash table,而這需花的時間是O(n)。之後就可以直接查Hash Table找到交集元素。建hash table的O(n)比BCR小,不會有任何額外付出。 - BCR告訴我們執行時間已最佳化要無法再優化了,應該要改善其**空間複雜度了**。 - 如果題目前提是「有序」的陣列,如此有機會去掉雜湊桶,減少額外空間,又能在O(n)中解決問題。 - 如果已達成BCR且具有O(1)額外空間(const)。我們知道已不能再做任何最佳化Big O時間或空間,這就是最佳解。 # Ref 解題時的測試與BCR: https://lucrelin.blogspot.com/2019/05/bcr.html WORKING TOWARDS BEST CONCEIVABLE RUNTIME (BCR): https://4tee-learn.blogspot.com/2019/04/working-towards-best-conceivable.html book: cracking the coding interview