typealiasValidationResult=(valid:Bool?,message:String?)funcvalidateUsername(username:String)->Observable<ValidationResult>{ifusername.characters.count==0{returnjust((false,nil))}// this obviously won't beifusername.rangeOfCharacterFromSet(NSCharacterSet.alphanumericCharacterSet().invertedSet)!=nil{returnjust((false,"Username can only contain numbers or digits"))}letloadingValue=(valid:nilasBool?,message:"Checking availabilty ..."asString?)returnAPI.usernameAvailable(username).map{availableinifavailable{return(true,"Username available")}else{return(false,"Username already taken")}}.startWith(loadingValue)}
Sometimes I need to update UI from different Fragments. But it seems that writing update method in each Fragment is absurd if I have a lot of Fragment to handle with.
Here is a better solution by using Observer pattern, IMO.
Sample
Define an EventObject, which is a event(or message) will be passed to Observer.
publicclassViewPagerTabsextendsLinearLayoutimplementsObserver{/* ... */@Overridepublicvoidupdate(Observableobservable,Objectdata){// TODO Auto-generated method stubViewPagerTabsUIEventObjecteventObject=(ViewPagerTabsUIEventObject)data;switch(eventObject.getEventType()){caseLABEL_OFF:// do somethingbreak;caseLABEL_ON:// do something elsebreak;default:break;}}}
In android development, Dialog are DialogFragment are very common UI parts. They come with a default border, with black or white background depending on android system version.
The default border, which is actually a drawable, is defined in android themes file.
Also, there are other dialog styles defined in android themes file.
1234567891011121314151617181920212223242526
<!-- Variant of {@link Theme_Dialog} that does not include a frame (or background).
The view hierarchy of the dialog is responsible for drawing all of
its pixels. -->
<style name="Theme.Dialog.NoFrame">
<item name="windowBackground">@color/transparent</item>
<item name="windowFrame">@null</item>
<item name="windowContentOverlay">@null</item>
<item name="windowAnimationStyle">@null</item>
<item name="backgroundDimEnabled">false</item>
<item name="windowIsTranslucent">true</item>
<item name="windowNoTitle">true</item>
<item name="windowCloseOnTouchOutside">false</item>
</style>
<!-- Default theme for alert dialog windows (on API level 10 and lower), which is used by the
{@link android.app.AlertDialog} class. This is basically a dialog
but sets the background to empty so it can do two-tone backgrounds. -->
<style name="Theme.Dialog.Alert">
<item name="windowBackground">@color/transparent</item>
<item name="windowTitleStyle">@style/DialogWindowTitle</item>
<item name="windowContentOverlay">@null</item>
<item name="itemTextAppearance">@style/TextAppearance.Large.Inverse</item>
<item name="textAppearanceListItem">@style/TextAppearance.Large.Inverse</item>
<item name="textAppearanceListItemSmall">@style/TextAppearance.Large.Inverse</item>
<item name="textAppearanceListItemSecondary">@style/TextAppearance.Small.Inverse</item>
</style>
importjava.util.*;publicclassTrafficCamera{privateintrootIndex=0;privateintlargestId=0;privateintsortedSubtreeDiameters[]=newint[50001];privateNodenodeMap[]=newNode[50001];privatebooleanvisited[]=newboolean[50001];privateintdiameter[]=newint[50001];staticclassNode{publicintid;publicList<Integer>edgeList;publicNode(intv){this.id=v;edgeList=newArrayList<Integer>();}publicvoidaddEdge(Integert){edgeList.add(t);}}publicintsolution(int[]A,int[]B,intK){intn=A.length;for(inti=0;i<n;i++){if(nodeMap[A[i]]==null){nodeMap[A[i]]=newNode(A[i]);}if(nodeMap[B[i]]==null){nodeMap[B[i]]=newNode(B[i]);}finalNodena=nodeMap[A[i]];finalNodenb=nodeMap[B[i]];na.addEdge(B[i]);nb.addEdge(A[i]);largestId=Math.max(largestId,A[i]);largestId=Math.max(largestId,B[i]);}rootIndex=A[0];intres=Integer.MAX_VALUE;intlow=0,high=Math.min(900,largestId);while(low<=high){intmid=(low+high)/2;if(isAvailabel(K,mid)){res=Math.min(res,mid);high=mid-1;}else{low=mid+1;}}returnres;}publicbooleanisAvailabel(intcameraLimit,intnotCoveredLength){for(inti=0;i<visited.length;i++)visited[i]=false;for(inti=0;i<diameter.length;i++)diameter[i]=-1;if(dfs(nodeMap[rootIndex],notCoveredLength)>cameraLimit){returnfalse;}returntrue;}privateintdfs(Nodenode,intlimit){if(node==null||visited[node.id]){return0;}visited[node.id]=true;intcounter=0;for(Integerid:node.edgeList){counter+=dfs(nodeMap[id],limit);}/* @ / \ @ @(current) / \ / \\\ @ @ a b c d step 1: Sort diameters of subtrees in reverse order, store them in an array step 2: For each adjacent pair in the sorted array, e.g. (a, b), (b, c), (c, d). If a + b + 2 > limit, we break the edge connecting current node to a, and counter plus 1. Do the same for (b, c) and (c, d). Note that, if (a, b) passed the test, we don't need to anymore because (a, b) is the largest pair of them. step 3: For last child d. or if current node has only one child. If d + 1 > limit, we break the edge connecting current node to a, and counter plus 1. step 4: Set diameter of current node to the largest one of the remains(not broken ones). *//* step 1 */intn=0;for(Integerid:node.edgeList){if(diameter[id]!=-1){sortedSubtreeDiameters[n++]=(diameter[id]);}}Arrays.sort(sortedSubtreeDiameters,0,n);for(inti=0;i<n/2;i++){// reverse orderinttemp=sortedSubtreeDiameters[i];sortedSubtreeDiameters[i]=sortedSubtreeDiameters[n-1-i];sortedSubtreeDiameters[n-1-i]=temp;}/* step 2 */intmaxDiameterAfterRemoval=-1;for(inti=0;i<n-1;i++){if(sortedSubtreeDiameters[i]+sortedSubtreeDiameters[i+1]+2>limit){counter++;}else{maxDiameterAfterRemoval=Math.max(maxDiameterAfterRemoval,sortedSubtreeDiameters[i]);break;// Even the largest pair is in the limit, we don't need check the remaining pairs.}}/* step 3 */if(n>=1){inti=n-1;if(sortedSubtreeDiameters[i]+1>limit){counter++;}else{maxDiameterAfterRemoval=Math.max(maxDiameterAfterRemoval,sortedSubtreeDiameters[i]);}}/* step 4 */// if subtrees are all removed, we can treat current node as a leaf, so diameter becomes 0if(maxDiameterAfterRemoval==-1){diameter[node.id]=0;}else{// if still some subtrees remain, then set current node's diameter as one plus the largestdiameter[node.id]=maxDiameterAfterRemoval+1;}returncounter;}}
In computer science, the longest increasing subsequence problem is to find a subsequence of a given sequence in which the subsequence’s elements are in sorted order, lowest to highest, and in which the subsequence is as long as possible.
For example, a longest increasing subsequence of 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15 is 0, 2, 6, 9, 11, 15.
An O(N2) Solution
We define a $dp$ table, which $dp[i]$ is the length of a longest subsequence which ends at $inputs[i]$.
For each $inputs[i]$, we search every inputs before it, and choose the longest possible $dp$ value from them, fill it in $dp[i]$.
We define a $seq$ table, which $seq[i]$ is the ending number of subsequence whose length is $i$.
Note that, $seq$ is always in increasing order.
Because if these exist $i < j$ and $seq[i] > seq[j]$, which means a longer subsequence end with a smaller number.
Then we could generate a new subsequence, which length is $i$, by removing $j - i$ numbers from tail of $j$-length subsequence. The ending number of the new subsequence will be smaller than $seq[i]$.
Therefore, we can use binary search in each iteration, to find the largest $seq[k]$ which is smaller than $inputs[i]$. If $k$ can be found ($k > -1$), then we update the number stored in $seq[k]$ with $inputs[i]$ if $inputs[i] < seq[k]$.
privateint[]seq=newint[128];publicintsolution2(){for(inti=0;i<seq.length;i++){seq[i]=Integer.MAX_VALUE;}intres=Integer.MIN_VALUE;for(inti=0;i<inputs.length;i++){intlongest=1;intbestSeqLength=binarySearch(seq,0,i,inputs[i]);if(bestSeqLength>-1){longest=bestSeqLength+1;}seq[longest]=Math.min(seq[longest],inputs[i]);res=Math.max(res,longest);}returnres;}publicintbinarySearch(int[]array,intbegin,intend,inttarget){ints=begin;intt=end;intm=s;intresult=-1;// !!!while(s<=t){m=(s+t)/2;if(array[m]<target){s=m+1;result=m;// result index, which array.get(result) is most close to & less than target}elseif(array[m]==target){returnm;}else{t=m-1;}}returnresult;}
We should use String.Index to handle different byte length of each character, and also decomposed and precomposed characters.
Because String in Swift is implemented as Unicode Scalar, or UTF-32, is always 4-byte long for each character and it default behaviour can handle composed characters.
A Unicode scalar is any Unicode code point in the range U+0000 to U+D7FF inclusive or U+E000 to U+10FFFF inclusive. Unicode scalars do not include the Unicode surrogate pair code points, which are the code points in the range U+D800 to U+DFFF inclusive.
classSuccessContainer<T>{init(t:T){// ...}}classErrorContainer<T>{init(t:T){// ...}}enumAPIResponse<JsonType,ErrorMsgType>{caseSuccess(SuccessContainer<JsonType>)caseFail(ErrorContainer<ErrorMsgType>)}// usagefuncGenAPIResponseSuccess<JsonType,ErrorMsgType>(json:JsonType)->APIResponse<JsonType,ErrorMsgType>{return.Success(SuccessContainer<JsonType>(t:json))}funcGenAPIResponseFail<JsonType,ErrorMsgType>(errorMsg:ErrorMsgType)->APIResponse<JsonType,ErrorMsgType>{return.Fail(ErrorContainer<ErrorMsgType>(t:errorMsg))}funccallbackFromAPI(response:String)->APIResponse<String,String>{if(response.hasPrefix("success")){returnGenAPIResponseSuccess(response)// can be parsed to json}else{returnGenAPIResponseFail(response)// just a plain error msg}}callbackFromAPI("success. I'm Json")callbackFromAPI("404 or something else")
But it is awful to write bunch of code for creating container classes, for each type you need.
publicfinalclassBox<T>:BoxType,Printable{/// Initializes a `Box` with the given value.publicinit(_value:T){self.value=value}/// Constructs a `Box` with the given `value`.publicclassfuncunit(value:T)->Box<T>{returnBox(value)}/// The (immutable) value wrapped by the receiver.publicletvalue:T/// Constructs a new Box by transforming `value` by `f`.publicfuncmap<U>(@noescapef:T->U)->Box<U>{returnBox<U>(f(value))}// MARK: Printablepublicvardescription:String{returntoString(value)}}
Finally
We can rewrite above code into this. Much more elegant.
1234567891011121314151617181920212223
enumAPIResponse2<JsonType,ErrorMsgType>{caseSuccess(Box<JsonType>)caseFail(Box<ErrorMsgType>)}funcGenAPIResponseSuccess2<JsonType,ErrorMsgType>(json:JsonType)->APIResponse2<JsonType,ErrorMsgType>{return.Success(Box<JsonType>(json))}funcGenAPIResponseFail2<JsonType,ErrorMsgType>(errorMsg:ErrorMsgType)->APIResponse2<JsonType,ErrorMsgType>{return.Fail(Box<ErrorMsgType>(errorMsg))}funccallbackFromAPI2(response:String)->APIResponse2<String,String>{if(response.hasPrefix("success")){returnGenAPIResponseSuccess2(response)// can be parsed to json}else{returnGenAPIResponseFail2(response)// just a plain error msg}}callbackFromAPI2("success. I'm Json")callbackFromAPI2("404 or something else")