Alice has some number of cards and she wants to rearrange the cards into groups so that each group is of size groupSize, and consists of groupSize consecutive cards.
Given an integer array hand where hand[i] is the value written on the ith card and an integer groupSize, return true if she can rearrange the cards, or false otherwise.
Example 1:
Input: hand = [1,2,3,6,2,3,4,7,8], groupSize = 3
Output: true
Explanation: Alice's hand can be rearranged as [1,2,3],[2,3,4],[6,7,8]
Example 2:
Input: hand = [1,2,3,4,5], groupSize = 4
Output: false
Explanation: Alice's hand can not be rearranged into groups of 4.
We first check whether the length of the array \(\textit{hand}\) is divisible by \(\textit{groupSize}\). If it is not, this means that the array cannot be partitioned into multiple subarrays of length \(\textit{groupSize}\), so we return \(\text{false}\).
Next, we use a hash table \(\textit{cnt}\) to count the occurrences of each number in the array \(\textit{hand}\), and then we sort the array \(\textit{hand}\).
After that, we iterate over the sorted array \(\textit{hand}\). For each number \(x\), if \(\textit{cnt}[x] \neq 0\), we enumerate every number \(y\) from \(x\) to \(x + \textit{groupSize} - 1\). If \(\textit{cnt}[y] = 0\), it means that we cannot partition the array into multiple subarrays of length \(\textit{groupSize}\), so we return \(\text{false}\). Otherwise, we decrement \(\textit{cnt}[y]\) by \(1\).
If the iteration completes successfully, it means that the array can be partitioned into multiple valid subarrays, so we return \(\text{true}\).
The time complexity is \(O(n \times \log n)\), and the space complexity is \(O(n)\), where \(n\) is the length of the array \(\textit{hand}\).
Similar to Solution 1, we first check whether the length of the array \(\textit{hand}\) is divisible by \(\textit{groupSize}\). If it is not, this means that the array cannot be partitioned into multiple subarrays of length \(\textit{groupSize}\), so we return \(\text{false}\).
Next, we use an ordered set \(\textit{sd}\) to count the occurrences of each number in the array \(\textit{hand}\).
Then, we repeatedly take the smallest value \(x\) from the ordered set and enumerate each number \(y\) from \(x\) to \(x + \textit{groupSize} - 1\). If all these numbers appear at least once in the ordered set, we decrement their occurrence count by \(1\). If any count reaches \(0\), we remove that number from the ordered set. Otherwise, if we encounter a number that does not exist in the ordered set, it means that the array cannot be partitioned into valid subarrays, so we return \(\text{false}\). If the iteration completes successfully, it means that the array can be partitioned into multiple valid subarrays, so we return \(\text{true}\).
The time complexity is \(O(n \times \log n)\), and the space complexity is \(O(n)\), where \(n\) is the length of the array \(\textit{hand}\).
functionisNStraightHand(hand:number[],groupSize:number):boolean{if(hand.length%groupSize!==0){returnfalse;}consttm=newTreeMap<number,number>();for(constxofhand){tm.set(x,(tm.get(x)||0)+1);}while(tm.size()){constx=tm.first()![0];for(lety=x;y<x+groupSize;++y){if(!tm.has(y)){returnfalse;}if(tm.get(y)!===1){tm.delete(y);}else{tm.set(y,tm.get(y)!-1);}}}returntrue;}typeCompare<T>=(lhs:T,rhs:T)=>number;classRBTreeNode<T=number>{data:T;count:number;left:RBTreeNode<T>|null;right:RBTreeNode<T>|null;parent:RBTreeNode<T>|null;color:number;constructor(data:T){this.data=data;this.left=this.right=this.parent=null;this.color=0;this.count=1;}sibling():RBTreeNode<T>|null{if(!this.parent)returnnull;// sibling null if no parentreturnthis.isOnLeft()?this.parent.right:this.parent.left;}isOnLeft():boolean{returnthis===this.parent!.left;}hasRedChild():boolean{return(Boolean(this.left&&this.left.color===0)||Boolean(this.right&&this.right.color===0));}}classRBTree<T>{root:RBTreeNode<T>|null;lt:(l:T,r:T)=>boolean;constructor(compare:Compare<T>=(l:T,r:T)=>(l<r?-1:l>r?1:0)){this.root=null;this.lt=(l:T,r:T)=>compare(l,r)<0;}rotateLeft(pt:RBTreeNode<T>):void{constright=pt.right!;pt.right=right.left;if(pt.right)pt.right.parent=pt;right.parent=pt.parent;if(!pt.parent)this.root=right;elseif(pt===pt.parent.left)pt.parent.left=right;elsept.parent.right=right;right.left=pt;pt.parent=right;}rotateRight(pt:RBTreeNode<T>):void{constleft=pt.left!;pt.left=left.right;if(pt.left)pt.left.parent=pt;left.parent=pt.parent;if(!pt.parent)this.root=left;elseif(pt===pt.parent.left)pt.parent.left=left;elsept.parent.right=left;left.right=pt;pt.parent=left;}swapColor(p1:RBTreeNode<T>,p2:RBTreeNode<T>):void{consttmp=p1.color;p1.color=p2.color;p2.color=tmp;}swapData(p1:RBTreeNode<T>,p2:RBTreeNode<T>):void{consttmp=p1.data;p1.data=p2.data;p2.data=tmp;}fixAfterInsert(pt:RBTreeNode<T>):void{letparent=null;letgrandParent=null;while(pt!==this.root&&pt.color!==1&&pt.parent?.color===0){parent=pt.parent;grandParent=pt.parent.parent;/* Case : A Parent of pt is left child of Grand-parent of pt */if(parent===grandParent?.left){constuncle=grandParent.right;/* Case : 1 The uncle of pt is also red Only Recoloring required */if(uncle&&uncle.color===0){grandParent.color=0;parent.color=1;uncle.color=1;pt=grandParent;}else{/* Case : 2 pt is right child of its parent Left-rotation required */if(pt===parent.right){this.rotateLeft(parent);pt=parent;parent=pt.parent;}/* Case : 3 pt is left child of its parent Right-rotation required */this.rotateRight(grandParent);this.swapColor(parent!,grandParent);pt=parent!;}}else{/* Case : B Parent of pt is right child of Grand-parent of pt */constuncle=grandParent!.left;/* Case : 1 The uncle of pt is also red Only Recoloring required */if(uncle!=null&&uncle.color===0){grandParent!.color=0;parent.color=1;uncle.color=1;pt=grandParent!;}else{/* Case : 2 pt is left child of its parent Right-rotation required */if(pt===parent.left){this.rotateRight(parent);pt=parent;parent=pt.parent;}/* Case : 3 pt is right child of its parent Left-rotation required */this.rotateLeft(grandParent!);this.swapColor(parent!,grandParent!);pt=parent!;}}}this.root!.color=1;}delete(val:T):boolean{constnode=this.find(val);if(!node)returnfalse;node.count--;if(!node.count)this.deleteNode(node);returntrue;}deleteAll(val:T):boolean{constnode=this.find(val);if(!node)returnfalse;this.deleteNode(node);returntrue;}deleteNode(v:RBTreeNode<T>):void{constu=BSTreplace(v);// True when u and v are both blackconstuvBlack=(u===null||u.color===1)&&v.color===1;constparent=v.parent!;if(!u){// u is null therefore v is leafif(v===this.root)this.root=null;// v is root, making root nullelse{if(uvBlack){// u and v both black// v is leaf, fix double black at vthis.fixDoubleBlack(v);}else{// u or v is redif(v.sibling()){// sibling is not null, make it red"v.sibling()!.color=0;}}// delete v from the treeif(v.isOnLeft())parent.left=null;elseparent.right=null;}return;}if(!v.left||!v.right){// v has 1 childif(v===this.root){// v is root, assign the value of u to v, and delete uv.data=u.data;v.left=v.right=null;}else{// Detach v from tree and move u upif(v.isOnLeft())parent.left=u;elseparent.right=u;u.parent=parent;if(uvBlack)this.fixDoubleBlack(u);// u and v both black, fix double black at uelseu.color=1;// u or v red, color u black}return;}// v has 2 children, swap data with successor and recursethis.swapData(u,v);this.deleteNode(u);// find node that replaces a deleted node in BSTfunctionBSTreplace(x:RBTreeNode<T>):RBTreeNode<T>|null{// when node have 2 childrenif(x.left&&x.right)returnsuccessor(x.right);// when leafif(!x.left&&!x.right)returnnull;// when single childreturnx.left??x.right;}// find node that do not have a left child// in the subtree of the given nodefunctionsuccessor(x:RBTreeNode<T>):RBTreeNode<T>{lettemp=x;while(temp.left)temp=temp.left;returntemp;}}fixDoubleBlack(x:RBTreeNode<T>):void{if(x===this.root)return;// Reached rootconstsibling=x.sibling();constparent=x.parent!;if(!sibling){// No sibiling, double black pushed upthis.fixDoubleBlack(parent);}else{if(sibling.color===0){// Sibling redparent.color=0;sibling.color=1;if(sibling.isOnLeft())this.rotateRight(parent);// left caseelsethis.rotateLeft(parent);// right casethis.fixDoubleBlack(x);}else{// Sibling blackif(sibling.hasRedChild()){// at least 1 red childrenif(sibling.left&&sibling.left.color===0){if(sibling.isOnLeft()){// left leftsibling.left.color=sibling.color;sibling.color=parent.color;this.rotateRight(parent);}else{// right leftsibling.left.color=parent.color;this.rotateRight(sibling);this.rotateLeft(parent);}}else{if(sibling.isOnLeft()){// left rightsibling.right!.color=parent.color;this.rotateLeft(sibling);this.rotateRight(parent);}else{// right rightsibling.right!.color=sibling.color;sibling.color=parent.color;this.rotateLeft(parent);}}parent.color=1;}else{// 2 black childrensibling.color=0;if(parent.color===1)this.fixDoubleBlack(parent);elseparent.color=1;}}}}insert(data:T):boolean{// search for a position to insertletparent=this.root;while(parent){if(this.lt(data,parent.data)){if(!parent.left)break;elseparent=parent.left;}elseif(this.lt(parent.data,data)){if(!parent.right)break;elseparent=parent.right;}elsebreak;}// insert node into parentconstnode=newRBTreeNode(data);if(!parent)this.root=node;elseif(this.lt(node.data,parent.data))parent.left=node;elseif(this.lt(parent.data,node.data))parent.right=node;else{parent.count++;returnfalse;}node.parent=parent;this.fixAfterInsert(node);returntrue;}search(predicate:(val:T)=>boolean,direction:'left'|'right'):T|undefined{letp=this.root;letresult=null;while(p){if(predicate(p.data)){result=p;p=p[direction];}else{p=p[direction==='left'?'right':'left'];}}returnresult?.data;}find(data:T):RBTreeNode<T>|null{letp=this.root;while(p){if(this.lt(data,p.data)){p=p.left;}elseif(this.lt(p.data,data)){p=p.right;}elsebreak;}returnp??null;}count(data:T):number{constnode=this.find(data);returnnode?node.count:0;}*inOrder(root:RBTreeNode<T>=this.root!):Generator<T,undefined,void>{if(!root)return;for(constvofthis.inOrder(root.left!))yieldv;yieldroot.data;for(constvofthis.inOrder(root.right!))yieldv;}*reverseInOrder(root:RBTreeNode<T>=this.root!):Generator<T,undefined,void>{if(!root)return;for(constvofthis.reverseInOrder(root.right!))yieldv;yieldroot.data;for(constvofthis.reverseInOrder(root.left!))yieldv;}}classTreeMap<K=number,V=unknown>{_size:number;tree:RBTree<K>;map:Map<K,V>=newMap();compare:Compare<K>;constructor(collection:Array<[K,V]>|Compare<K>=[],compare:Compare<K>=(l:K,r:K)=>(l<r?-1:l>r?1:0),){if(typeofcollection==='function'){compare=collection;collection=[];}this._size=0;this.compare=compare;this.tree=newRBTree(compare);for(const[key,val]ofcollection)this.set(key,val);}size():number{returnthis._size;}has(key:K):boolean{return!!this.tree.find(key);}get(key:K):V|undefined{returnthis.map.get(key);}set(key:K,val:V):boolean{constsuccessful=this.tree.insert(key);this._size+=successful?1:0;this.map.set(key,val);returnsuccessful;}delete(key:K):boolean{constdeleted=this.tree.deleteAll(key);this._size-=deleted?1:0;returndeleted;}ceil(target:K):[K,V]|undefined{returnthis.toKeyValue(this.tree.search(key=>this.compare(key,target)>=0,'left'));}floor(target:K):[K,V]|undefined{returnthis.toKeyValue(this.tree.search(key=>this.compare(key,target)<=0,'right'));}higher(target:K):[K,V]|undefined{returnthis.toKeyValue(this.tree.search(key=>this.compare(key,target)>0,'left'));}lower(target:K):[K,V]|undefined{returnthis.toKeyValue(this.tree.search(key=>this.compare(key,target)<0,'right'));}first():[K,V]|undefined{returnthis.toKeyValue(this.tree.inOrder().next().value);}last():[K,V]|undefined{returnthis.toKeyValue(this.tree.reverseInOrder().next().value);}shift():[K,V]|undefined{constfirst=this.first();if(first===undefined)returnundefined;this.delete(first[0]);returnfirst;}pop():[K,V]|undefined{constlast=this.last();if(last===undefined)returnundefined;this.delete(last[0]);returnlast;}toKeyValue(key:K):[K,V];toKeyValue(key:undefined):undefined;toKeyValue(key:K|undefined):[K,V]|undefined;toKeyValue(key:K|undefined):[K,V]|undefined{returnkey!=null?[key,this.map.get(key)!]:undefined;}*[Symbol.iterator]():Generator<[K,V],void,void>{for(constkeyofthis.keys())yieldthis.toKeyValue(key);}*keys():Generator<K,void,void>{for(constkeyofthis.tree.inOrder())yieldkey;}*values():Generator<V,undefined,void>{for(constkeyofthis.keys())yieldthis.map.get(key)!;returnundefined;}*rkeys():Generator<K,undefined,void>{for(constkeyofthis.tree.reverseInOrder())yieldkey;returnundefined;}*rvalues():Generator<V,undefined,void>{for(constkeyofthis.rkeys())yieldthis.map.get(key)!;returnundefined;}}