You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
lettext: string="the cat jumped over the dog";letoutput: StyledString[]=synhi(text);assert(output[0].content,"the ");assert(output[0].style,Style.None);assert(output[1].content,"cat");assert(output[1].style,Style.Bold);
Implement a ring buffer in TypeScript. The ring buffer is a queue abstract data type that’s implemented using a fixed size array.
This makes it performant with additions and deletions from a runtime and memory standpoint. Since it does not change its size once created, there's no overhead w/ increasing or shrinking the size of it's underlying array.
The ring buffer API is very similar to that of a queue; it hides the fact that there's a fixed size buffer that's underpinning its implementation.
When creating a ring buffer you have to specify it's size.
Here's some TS code that you might consider using to start implementing your ring buffer.
/** * RingBuffer uses a fixed length array to implement a queue, where, * - [tail] Items are added to the tail * - [head] Items are removed from the head * - [capacity] Keeps track of how many items are currently in the queue */classRingBuffer<T>{constructor(size: number);clear();enqueue(item: T);dequeue(): T?;peek(): T?;len(): number;}
Here's an example of how this ring buffer might be used:
Since the array is re-used for insertions and deletions, it becomes important to be able to track the usage or capacity of the array (as items are added and removed). This capacity is used to determine whether the array is full or empty, and is used to iterate thru the elements of the array if needed.
In order to cycle around the array, the head and tail indices are updated such that when they hit the “end” of the array, they “flip” over. This means that when head reaches maxSize + 1, it just goes to 0. This can be achieved easily by using the % operator. tail = (tail+1) % maxSize is the equivalent of if (tail == maxSize) tail = 0.
In order to get all the elements out of the array (as a list) the capacity and the head (or read index) is used in order to get all the elements out as we would expect (which isn’t necessarily how they are laid out in the array).
Let's say that you are working on a text editor application. This editor allows lines of plain text
to be edited by a user who is running this application. More details about this application are not
provided.
The task is to create a function that will allow the user to move the caret to the left
and to the right. The details about how these input events are captured are not provided.
Note that this function will mutate the argument that is passed in. This is not
a pure function.
Expected usage
And here is what a test might look like. However, this test is not exhaustive and doesn't really
capture all the edge cases. As a bonus, you can provide a test w/ the edge cases (eg: caret is at
the end of a line and is moved to the right, but there are no more lines, etc.)
Let's say that you are working on a text editor application. This editor allows lines of plain text
to be edited by a user who is running this application. More details about this application are not
provided.
The task is to create a function that will clip the line at the caret, to a given start and end
position. This can happen in cases where you have a long line of text and the editor application
wants to display just a portion of the line to the end user.
Let's say that you are working on a text editor application. This editor allows lines of plain text
to be edited by a user who is running this application. More details about this application are not
provided.
The task is to create a function that will take a viewport (specified by origin position and size)
and clip the content to the viewport & return that as a new array of lines. This can happen in cases
where you have a many lines of text and each line can be very wide, and the editor application has
to clip the content to the viewport. This is something we take for granted in all modern GUI apps.
The caret is represented by a row and column index.
The lines are represented by a 2D array of strings (not chars).
The viewport is represented by:
row and column index
width and height.
Expected function signatures
Here's the function signatures that you need to implement:
functionclipToViewport(editorData,viewport);
This function will also return the clipped document itself which is the same shape as the lines
property of the editor data shown above. It does not modify the editor data (caret & lines).
Expected usage
And here is what a test might look like. However, this test is not exhaustive and doesn't really
capture all the edge cases.
File systems on computers have a hierarchical file system. Searching for a folder by name is a very
common thing to do on computers. On Unix machines, we can use the find folder_name
command. The task is to implement a very simplified version of this command.
Here's an example of a hierarchial folder structure on a Linux machine.
root <- On Linux, the root folder of the filesystem is `/`
+ opt <- insertion order must **not** preserved for folders
+ chrome
+ apps
+ idea
+ android_studio
+ dev
+ java
+ java11
+ java12
The first step of the task is to create a data structure that can be used to represent this type
of folder structure. Note that we are not concerned w/ the files that may be contained in a folder.
constroot=newFolder("root");letopt=root.addSubFolder(newFolder("opt"));letapps=root.addSubFolder(newFolder("apps"));letdev=root.addSubFolder(newFolder("dev"));opt.addSubFolder(newFolder("chrome"));// etc.
The second step of the task is to create a function that can search for a folder by name.
Expected function signature
Here's the function signatures that you need to implement:
Bonus # 0 - Search all the folder names in a given depth
The search() function does not return the path to the folder that is found and it doesn't report
how many folders were found. You can implement both these features as a bonus if you want.
So if we were searching the following hierarchy, for "java":
root <- On Linux, the root folder of the filesystem is `/`
+ opt <- insertion order **should** be preserved for folders
+ chrome
+ apps
+ idea
+ android_studio
+ java
+ dev
+ java
+ java11
+ java12
+ java
Bonus # 1 - Preserve the insertion order of sub folders
root <- On Linux, the root folder of the filesystem is `/`
+ opt <- insertion order **should** be preserved for folders
+ chrome
+ apps
+ idea
+ android_studio
+ dev
+ java
+ java11
+ java12
Bonus # 2 - Pretty print the tree to a string
Implement the following function that takes a Node and turns into a string that can be printed to
the terminal via console.log. Note that the depth of each folder is indicated by the number of
spaces before the folder name (each depth is 2 spaces, so depth of 0 is 0 spaces, depth of 1 is 2
spaces, depth of 2 is 4 spaces, and so on).
functionprettyPrint(root: Folder): string;
The string produced by this function might look something like:
root
opt
chrome
apps
idea
android_studio
dev
java
java11
java12
Also here's more information on tree traversal / walking on wikipedia
Caching is a very common and powerful technique used in computer programming. It is used to improve
the performance of applications by storing the results of expensive operations and returning the
cached result when the same operation is requested again.
The trick is to come up with a way to identify the input to the operation. This is called the
cache key. The cache key is used to look up the cached result for the operation. If the result is
found, it is returned immediately. If the result is not found, then the operation is performed and
the result is cached using the cache key.
Another trick is to come up with a way to identify when the cached result is no longer valid. This
is called the cache expiry or invalidation. The cache expiry or invalidation is used to determine
when the cached result should be discarded.
Here's a signature for a function that performs a very simple operation and returns a result:
functionexpensiveOperation(key: any): any;
The first step of the task is to create a class that can cache the results of the expensive
operation.
constcache=newCache();functionexpensiveOperation(key: any): any{// Some expensive operation happens here, but just calling stringify for now...returnJSON.stringify(key);}letresult=cache.get("foo",expensiveOperation);// runs expensiveOperation, returns JSON.stringify("foo")letresult2=cache.get("bar",expensiveOperation);// runs expensiveOperation, returns JSON.stringify("bar")letresult3=cache.get("foo",expensiveOperation);// returns cached result
The second step of the task is to provide a maximum capacity for the cache, and provide a way to
discard the least frequently used keys from the cache. This means that if a key is unpopular then
we discard it from the cache. If you have to choose between multiple keys to discard (since
they're all unpopular) then you can choose any one of them.
Expected function and class signatures
Here's an example of the code that you might write.
If you want to go the extra mile, when you are faced w/ discarding multiple unpopular keys, you
can choose the one that has been in the cache the longest (ie, discard the oldest one). This will
require you to change the implementation of the cache to keep track of the order in which the keys
were added to the cache.