The most easy way to solve to this problem is just make one pass for the input like below.

```
function findPeakElement(nums: number[]): number {
for (let i = 0; i < nums.length - 1; i++) {
if (nums[i] > nums[i + 1]) {
return i;
}
}
return nums.length - 1;
};
```

As you can see, the code is very simple, we only need to find the first element which is bigger than next element.

But in this way, the time complexity is `O(n)`

, how can we make it `O(log(n))`

? To make this happen, the first algotihm comes to my mind is binary search. So the problem becomes how can we apply binary search into this problem?

Well, to find one peak elment, there are 3 cases.

First is increaing array numbers:

```
[1, 2, 3, 4, 5]
```

Second is decreasing array numbers:

```
[5, 4, 3, 2, 1]
```

Third is first increasing and then decreasing:

```
[1, 3, 5, 4, 2]
```

So the key is, for every iteration among the binary search, we compare current middle value `nums[mid]`

with its next value `nums[mid+1]`

. If `nums[mid] > nums[mid+1]`

, then there must exist a peak element on the left. Else, then there must exist a peak element on the right.

For example, for 3 cases above, in the first iteration, the mid index is 2, so situations are like below.

```
[1, 2, 3, 4, 5], index 2 has value 3, 3 < 4, peak element on the right(nums.slice(3))
[5, 4, 3, 2, 1], index 2 has value 3, 3 > 2, peak element on the left(nums.slice(0, 3))
[1, 3, 5, 4, 2], index 2 has value 5, 5 > 4, peak element on the left(nums.slice(0, 3))
```

So, follow this process recursively, we can find one peak element.

```
function _findPeakElement(nums: number[], left: number, right: number): number {
if (left === right) return left;
const mid = left + Math.floor((right - left) / 2);
if (nums[mid] > nums[mid + 1]) {
return _findPeakElement(nums, left, mid);
} else {
return _findPeakElement(nums, mid + 1, right);
}
}
function findPeakElement(nums: number[]): number {
return _findPeakElement(nums, 0, nums.length - 1);
};
```

We can do this process iterately also.

```
function findPeakElement(nums: number[]): number {
let left = 0;
let right = nums.length - 1;
while (left < right) {
const mid = left + Math.floor((right - left) / 2);
if (nums[mid] > nums[mid + 1]) {
right = mid;
} else {
left = mid + 1;
}
}
return left;
};
```

In leetcode, there is also a problem Find a Peak Element II. It's like a 2d version of peak element finding problem.

However, even though we have develop an intuition on how to sovle the 1d version, it is not easy to understand how to do it in 2d version.

Can we simple run the 1d version solution on every row and every column? No, because the solution just found 1 peak element, not all of them, so there is no guarantee that we can find the same element which is both peak element in row and in column. In other words, we can't do it in `O(log(m)log(n))`

time.

But we can do it in `O(log(m)n)`

or `O(mlog(n))`

time. We can calaulate the max value on one dimension and use the binary search solution on another dimension. Now let's see how it works.

Say the grid is like below.

```
index
0 1 2 3 4
0 . . . . .
1 . . . . .
2 . . . . .
3 . . . . .
4 . . . . .
```

First, we move to the middle row, which is the row with index 2. Then we find the max value of the row, suppose the max value is `x`

like below.

```
index
0 1 2 3 4
0 . . . . .
1 . . . . .
2 . . . x .
3 . . . y .
4 . . . . .
```

Then we compare `x`

with next value on the grid, which is `y`

. If `x < y`

is true, just like in 1d version, we drop the first part. Now we have only half the grid.

```
index
0 1 2 3 4
...(dropped)
3 . . . . .
4 . . . . .
```

Because `x`

is the max value and `x < y`

, then we know for sure the max value on the row with index 3 is bigger than any value on the row with index 2.

Now follow the same process, we calculate the middle row, which is the row with index 3, then find its max value, we still use `x`

.

```
index
0 1 2 3 4
...(dropped)
3 . . x . .
4 . . y . .
```

We compare the max value `x`

with its next value `y`

.

Now, if `x>y`

, then `x`

is the peak element. How come? because `x`

is max value of the row, so row dimension is done. Because `x>y`

and `x`

is bigger than any value than values in row with index 2, then column demension is done. So in this case, `x`

is the peak element.

If `x<y`

, can we draw the conclusion that `y`

is the peak element? No, because `y`

may not bigger than element on the left or right. So what now? Now we find the max value of the row with index 4, suppose it is `z`

.

```
index
0 1 2 3 4
...(dropped)
3 . . x . .
4 . . y . z
```

Because `z`

is the max value of the row, so row is done. Because `x<y`

and `y<z`

, then `x<z`

. Because `x`

is the max value of row with index 3, so `z`

is bigger than any values in the row with index 3. So column is done. So in this case, `z`

is the peak element.

As you can see, for every step, we use max value to rule out one dimension(max value must be peak element), then we apply the binary search approach on another dimension. In above example, we calculate the max value of each row. Same approach goes with calculating max value on each column.

OK, now let's see the process in code.

```
// find max value, return [value, index]
function findMax(nums: number[]): [number, number] {
const result: [number, number] = [Number.MIN_SAFE_INTEGER, -1];
for (let i = 0; i < nums.length; i++) {
if (nums[i] > result[0]) {
result[0] = nums[i];
result[1] = i;
}
}
return result;
}
function findPeakGrid(mat: number[][]): number[] {
let startRowIndex = 0;
let endRowIndex = mat.length - 1;
while (startRowIndex < endRowIndex) {
const midRowIndex = startRowIndex + Math.floor((endRowIndex - startRowIndex) / 2);
const [maxValue, maxIndex] = findMax(mat[midRowIndex]);
const nextValue = mat[midRowIndex + 1][maxIndex];
// compare current max value with it's next value
// so we can rule out half grid
if (maxValue > nextValue) {
endRowIndex = midRowIndex;
} else {
startRowIndex = midRowIndex + 1;
}
}
// now we find target row, then we calculate max row value
const rowIndex = startRowIndex;
const [_, colIndex] = findMax(mat[rowIndex]);
return [rowIndex, colIndex];
};
```

]]>Because introspective sort uses those 3 algorithms, so let's implement them first.

Let's begin from the most simple one: selection sort. The idea is very simple, for every element, compare it with elements before it, move elements to the right until current element is bigger.

```
function insertionSort(nums: number[], left: number, right: number): void {
for (let i = left + 1; i <= right; i++) {
// current element as key
const key = nums[i];
// iterate from i-1 to left
// if nums[j] > key, then move nums[j] to the right
let j = i - 1;
for (; j >= left && nums[j] > key; j--) {
nums[j + 1] = nums[j];
}
// insert key into appropriate place
nums[j + 1] = key;
}
}
```

Next is heap sort. I wrote an article about heap sort before, so I will not repeat here. Check that article first if you are not familiar with it. Here is the code of heap sort.

```
type HeapqComparator<T> = (t1: T, t2: T) => boolean;
class heapq {
public static heapify<T>(elements: T[], comparator: HeapqComparator<T>) {
for (let i = elements.length - 1; i >= 0; i--) {
heapq._heapify(elements, i, comparator);
}
}
private static _heapify<T>(elements: T[], index: number, comparator: HeapqComparator<T>) {
const lci = index * 2 + 1;
const rci = index * 2 + 2;
let topi = index;
// note the arguments order the function comparator
// if its in heap, then we need elements[topi] - elements[lci] > 0
if (lci < elements.length && comparator(elements[topi], elements[lci])) {
topi = lci;
}
if (rci < elements.length && comparator(elements[topi], elements[rci])) {
topi = rci;
}
if (topi !== index) {
[elements[topi], elements[index]] = [elements[index], elements[topi]];
heapq._heapify(elements, topi, comparator);
}
}
public static heappush<T>(elements: T[], val: T, comparator: HeapqComparator<T>) {
elements.push(val);
heapq._swapWithParent(elements, elements.length - 1, comparator);
}
private static _swapWithParent<T>(elements: T[], index: number, comparator: HeapqComparator<T>) {
if (index === 0) return;
const pi = Math.trunc((index - 1) / 2);
// note the arguments order the function comparator
// if its min heap, then we need elements[pi] - elements[index] > 0
if (comparator(elements[pi], elements[index])) {
[elements[index], elements[pi]] = [elements[pi], elements[index]];
heapq._swapWithParent(elements, pi, comparator);
}
}
public static heappop<T>(elements: T[], comparator: HeapqComparator<T>): T {
const res = elements[0];
elements[0] = elements[elements.length - 1];
elements.splice(elements.length - 1, 1);
heapq._heapify(elements, 0, comparator);
return res;
}
}
function heapSort(nums: number[]) {
const comparator = (a: number, b: number) => (a - b) > 0;
const heapNums = [...nums];
heapq.heapify(heapNums, comparator);
for (let i = 0; i < nums.length; i++) {
nums[i] = heapq.heappop(heapNums, comparator);
}
}
```

OK, now let's see how introsort combines quick sort with heap sort and selection sort.

Introsort use quick sort as a base sort algorithm. When some conditions are met, then switch to other algorithms.

The first condition is, for every iteration from the quick sort, if current array's length is lower then 16, then use quick sort. This decision is because, even if the time complexity of selection sort is `O(n^2)`

, for small array, selection sort usually runs faster.

The second condition is, introsort defined a max depth value according to the length of the array. We know that if we can't choose the right pivot in quick sort, then the time complexity can becomes `O(n^2)`

. So to prevent this case, when the process of quick sort run out of the depth limit, then we just give up quick sort, and switch to heap sort.

Yes, that's all the details. Let's implement it in code.

```
function partition(nums: number[], low: number, high: number): number {
let pivot = nums[high];
let p = low;
for (let i = low; i < high; i++) {
if (nums[i] <= pivot) {
[nums[i], nums[p]] = [nums[p], nums[i]];
p += 1;
}
}
[nums[high], nums[p]] = [nums[p], nums[high]];
return p;
}
function _introSort(nums: number[], left: number, right: number, depthLimit: number) {
if (left > right) return;
if (right - left < 16) {
// size is lower then 16, use insertion sort
insertionSort(nums, left, right);
} else {
if (depthLimit <= 0) {
// run out of depth limit, switch to heap sort
heapSort(nums);
} else {
// run normal quick sort process
const mid = partition(nums, left, right);
_introSort(nums, left, mid - 1, depthLimit - 1);
_introSort(nums, mid + 1, right, depthLimit - 1);
}
}
}
function introSort(nums: number[]) {
const left = 0;
const right = nums.length - 1;
// predefined the depth limit
const depthLimit = 2 * Math.floor(Math.log2(nums.length));
_introSort(nums, left, right, depthLimit);
}
```

]]>The quick sort algorithm is a divide and conquer algorithm. Specifically, we choose a pivot, then move element to make left part lower than pivot, and right part bigger than pivot. So for one loop, we split the array into 2 half.

The key here is that how we split the array. In previous article, we just use a simple approach, select the last element of the array and use it as the pivot the split the array. In that case, we assume the array is random, so the time complexity is `O(nlog(n))`

in average. But if the array is sorted, then when we select the last element as pivot, we can't split the array into 2 half because this pivot is the max or min value. So in this case, the time complexity becomes `O(n^2)`

.

The median of three strategy is a technique to make the pivot selection part more smart. Specifically, for every iteration, we will choose 3 values as candidates for pivot. We calculate the median of the 3 values, then choose it as the pivot.

The code is very simple to implement. In typical quick sort partition function, we choose the last element directly.

```
function partition(nums: number[], low: number, high: number): number {
let pivot = nums[high];
let p = low;
for (let i = low; i < high; i++) {
if (nums[i] <= pivot) {
[nums[i], nums[p]] = [nums[p], nums[i]];
p += 1;
}
}
[nums[high], nums[p]] = [nums[p], nums[high]];
return p;
}
```

By using the median of three, we will compare low and mid element, and choose the median one.

```
function partition(nums: number[], low: number, high: number): number {
const mid = low + Math.floor((high - low) / 2);
if (
(nums[low] > nums[mid] && nums[low] < nums[high]) ||
(nums[low] < nums[mid] && nums[low] > nums[high])
) {
[nums[low], nums[high]] = [nums[high], nums[low]];
} else if (
(nums[mid] > nums[low] && nums[mid] < nums[high]) ||
(nums[mid] < nums[low] && nums[mid] > nums[high])
) {
[nums[mid], nums[high]] = [nums[high], nums[mid]];
}
// the same as above
}
```

Note that if the median value is not the high value, we can simple swap the median value with the high value, so the other part remains the same.

As you can see, in this way, we can limit the number of worse cases.

To calculate the median value, we can use `xor`

to speed up the operations. For example, if the low value is the median value, then `+(nums[low] > nums[mid])`

and `+(nums[low] > nums[high])`

should one has value 1, the other has value 0, then we use `xor`

to make it 1. Same thing goes with the mid value.

```
function partition(nums: number[], low: number, high: number): number {
const mid = low + Math.floor((high - low) / 2);
if ((+(nums[low] > nums[mid])) ^ (+(nums[low] > nums[high]))) {
[nums[low], nums[high]] = [nums[high], nums[low]];
} else if ((+(nums[mid] < nums[low])) ^ (+(nums[mid] < nums[high]))) {
[nums[mid], nums[high]] = [nums[high], nums[mid]];
}
// the same as above
}
```

]]>As the problem requires, the operation is very much like a rotation. We can think of the matrix as an image and we need to rotate the image by 90 degrees (clockwise).

The rotation operation is easy, what makes this problem harder is that we need to do it in-place. So we need to figure out a way to store the temporary state within the matrix. Let's see an example.

Suppose the matrix is below.

```
1 2 3
4 5 6
7 8 9
```

To find out a pattern, let consider only the first value.

```
move 1 to target place
1 x 3 1 x 1
x x x => x x x
7 x 9 7 x 9
```

The value replaced by 1 is 3, let see where 3 goes.

```
1 x 1 1 x 1
x x x => x x x
7 x 9 7 x 3
```

Follow the same pattern.

```
1 x 1 1 x 1 7 x 1
x x x => x x x => x x x
7 x 3 9 x 3 9 x 3
```

Now you can see that we finished one rotation for the first value. For every step, we only need one variable to store the previous number.

Same pattern goes with other values. We can just follow this pattern to iterate all values to solve this problem. The visualization and code in leetcode describe this solution very well.

But this is not what this article for. I'm interested with this problem is because it is can be solved by classic matrix operation: transpose and reflect.

Matrix transpose is an operation to make each row to be each column. Below show that first row `1,2,3`

becomes first column `1,2,3`

. Same things goes with other rows.

```
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
transpose
[
[1, 4, 7],
[2, 5, 8],
[3, 6, 9],
]
```

Well, then how to do transpose in code? This seems pretty complicated as well. Instead of values, let's write all coordinates to see if there is a pattern.

```
[
[(0,0), (0,1), (0,2)],
[(1,0), (1,1), (1,2)],
[(2,0), (2,1), (2,2)],
]
transpose
[
[(0,0), (1,0), (2,0)],
[(0,1), (1,1), (2,1)],
[(0,2), (1,2), (2,2)],
]
```

As you can see, if current cell's index is `(i,j)`

, to do transpose we can just swap its values with index `(j,i)`

. But we need to be careful about this. We don't need to do it for every value, because in that case we will do swap twice. Actually, we only need to do swap for below values.

```
[
[ (1,0), (2,0)],
[ (2,1)],
[ ],
]
```

OK, that's clear now. Let's do transpose in code.

```
function transpose(matrix: number[][]): void {
for (let i = 0; i < matrix.length; i++) {
for (let j = i + 1; j < matrix.length; j++) {
[matrix[i][j], matrix[j][i]] = [matrix[j][i], matrix[i][j]];
}
}
}
```

Then what is reflect? We can think of reflect as a mirror effect. We can choose to do reflect by x axis or y axis. Below shows the process of reflect by y axis.

```
[
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
]
reflect
[
[3, 2, 1],
[6, 5, 4],
[9, 8, 7],
]
```

Well, this seems easy. What we only need is to swap columns on the left with columns on the right. Let's see it in code.

```
function reflect(matrix: number[][]): void {
const mid = Math.floor(matrix.length / 2);
for (let i = 0; i < matrix.length; i++) {
for (let j = 0; j < mid; j++) {
[
matrix[i][j],
matrix[i][matrix.length - j - 1]
] = [
matrix[i][matrix.length - j - 1],
matrix[i][j]
];
}
}
}
```

OK, now we know how to do transpose and reflect on matrix. How these can be of help for solving this problem? Well, let's see the process in below.

```
1 2 3
4 5 6
7 8 9
transpose =>
1 4 7
2 5 8
3 6 9
reflect =>
7 4 1
8 5 2
9 6 3
```

So, what we only need to do is one transpose and one reflect, then problem solved.

```
function rotate(matrix: number[][]): void {
transpose(matrix);
reflect(matrix);
};
```

]]>We will start with this `char`

function just like before. It is a base parser, used to parse an arbitrary character.

```
const char = c => state => {
if (state.error) return state;
const { index, data } = state;
if (index >= data.length) {
return {
...state,
error: `char(): not enough data to parse, index: ${index}, char: ${c}`
};
}
const value = data.charAt(index);
if (value !== c) {
return {
...state,
error: `char(): parse error, index: ${index}, expect: ${c}, got: ${value}`
};
}
return {
...state,
index: index + 1,
value
};
};
```

Other than this, since we don't want to write all related character literals, so we need another base parser, we call it `nchar`

, meaning not specified character.

```
const nchar = c => state => {
if (state.error) return state;
const { index, data } = state;
if (index >= data.length) {
return {
...state,
error: `nchar(): not enough data to parse, index: ${index}, char: ${c}`
};
}
const value = data.charAt(index);
if (value === c) {
return {
...state,
error: `nchar(): parse error, index: ${index}, expect not: ${c}, got: ${value}`
};
}
return {
...state,
index: index + 1,
value
};
};
```

Just as the name goes, this function takes in one character, and is able to parse any character other than this input character. Later when we parse JSON string, we will need this.

Now comes the parser combinators. Below is the `and`

and `or`

function, just like before.

```
const _or = (p1, p2) => state => {
if (state.error) return state;
let nextState = p1(state);
if (!nextState.error) return nextState;
nextState = p2(state);
if (!nextState.error) return nextState;
return {
...state,
error: `error or`,
};
};
const or = (...parsers) => state => {
return parsers.reduce((p1, p2) => _or(p1, p2))(state);
};
const _and = (p1, p2) => state => {
if (state.error) return state;
let p1State = p1(state);
if (p1State.error) return p1State;
let p2State = p2(p1State);
if (p2State.error) return p2State;
return {
...p2State,
value: [p1State.value, p2State.value]
};
};
const and = (...parsers) => state => {
if (state.error) return state;
const parser = parsers.reduce((p1, p2) => {
return _and(p1, p2);
});
const nextState = parser(state);
if (nextState.error) return nextState;
nextState.value = nextState.value.flat(Infinity);
return nextState;
};
```

Other than these, we need some other more advanced parser combinators.

First one is `many`

. Like before, it is like the `*`

in regular expressions and can parse zero or multiple time by specified parser.

```
// like *
const many = parser => state => {
if (state.error) return state;
let value = [];
let pre = state;
while (true) {
state = parser(pre);
if (state.error) break;
value.push(state.value);
pre = state;
}
return {
...pre,
error: null,
value
};
};
```

To make things easy, we need a `many1`

function. It is like the `+`

in regular expressions and can parse one or multiple times by specified parser.

```
// like +
const many1 = parser => state => {
if (state.error) return state;
return and(parser, many(parser))(state);
};
```

And the last one, we call it `or1`

function. It is like the `?`

in regular expressions and can parse zero or 1 times by specified parser.

```
// like ?
const or1 = parser => state => {
if (state.error) return state;
const next = parser(state);
if (next.error) {
return state;
} else {
return next;
}
};
```

Of course, we need to define some utils. A `map`

function to convert parser result. A `createInitState`

function to initialize state. And a `lazy`

function, which is used to handle recursive parser function calls.

```
const map = (parser, fn) => state => {
if (state.error) return state;
state = parser(state);
if (state.error !== null) return state;
state.value = fn(state.value);
return state;
};
function createInitState(data) {
return {
data: data,
index: 0,
error: null,
value: [],
};
}
const lazy = thunk => state => thunk()(state);
```

OK, with these basic tools, we can begin to parse JSON data.

First, let define a few special character in JSON.

```
const zero = char("0");
const one = char("1");
const two = char("2");
const three = char("3");
const four = char("4");
const five = char("5");
const six = char("6");
const seven = char("7");
const eight = char("8");
const nine = char("9");
const character = nchar('"');
const doubleQuote = char('"');
const comma = char(",");
const leftBracket = char("[");
const rightBracket = char("]");
const colon = char(":");
const leftCurlyBracket = char("{");
const rightCurlyBracket = char("}");
```

Then we start with the most simple stuff, booleans and null.

```
const jtrue = map(
and(char("t"), char("r"), char("u"), char("e")),
_ => ({ type: "scalar", value: true })
);
const jfalse = map(
and(char("f"), char("a"), char("l"), char("s"), char("e")),
_ => ({ type: "scalar", value: false })
);
const jnull = map(
and(char("n"), char("u"), char("l"), char("l")),
_ => ({ type: "scalar", value: null })
);
```

As you can see, we use `map`

function to name all these tokens as type scalar, because these are not compound values like array or object. Same things go with the numbers and strings.

Now let see how to define a number parser.

```
const positiveDigit = or(one, two, three, four, five, six, seven, eight, nine);
const digit = or(positiveDigit, zero);
const jnumber = map(
and(
or1(char("-")),
or(
zero,
and(
positiveDigit,
many(digit)
)
)
),
value => ({ type: "scalar", value: Number(value.join("")) })
);
```

It may looks complicated at first, but it is just number. First, we use `or1`

to parse the negative character if there is one. Then if first character is zero, then we should step parsing. If not, then we should parse number as many as possible.

Then let's see how to define a string parser.

```
const characters = many(character);
const jstring = map(
and(doubleQuote, characters, doubleQuote),
value => ({ type: "scalar", value: value.slice(1, value.length - 1).join("") })
);
```

Remember in the beginning, we defined a parser `character`

which used the `nchar`

function to express any character other than double quote. It is defined in this way because in JSON, strings are using double quote as start and end mark. Then we can use `and`

function to express a string, starts and ends with double quotes.

Next since whitespace is very free in JSON, we need to define a parser to handle whitespaces.

```
const jwhitespace = map(
many(or(char(" "), char("\n"), char("\t"), char("\r"))),
value => value.join("")
);
```

OK, now we have defined quite a few parser for JSON tokens. All these in JSON are called JSON values. Let's define a parser to combine these together.

```
const jvalue = or(
jstring,
jnumber,
jtrue,
jfalse,
jnull
);
```

Based on this, let's think about how to handle arrays. The format of arrays in JSON is pretty free. But basically, it is surrounded by brackets and filled with values. Typical examples are like below.

```
[] // empty array, ok
[1] // array with only 1 element, ok
[1,2,3] // array with multiple element, ok
[1,true,null] // array with different types of elements, ok
[ 1, 3 ] // array filled with arbitrary number of whitespaces, ok
```

OK, let's start with simple ones. Since array elements can be surrounded by whitespaces, so we define a special parser for one element.

```
const jelement = map(
and(
jwhitespace,
jvalue,
jwhitespace,
),
value => value[1]
);
```

Then we consider multiple elements. In JSON, the last element in array should not followed by a comma. So we use `or`

to express this limit.

```
const jelements = or(
and(jelement, comma, lazy(() => jelements)),
jelement,
);
```

Note that here, since we don't know the number of elements in array, so we use a recursive approach to parse it.

Now we can define our array parser, which only contains two cases: empty array or not empty array. We use `or`

function to express this format and use some `map`

function to make the result clearly.

```
const jarray = map(
or(
map(
and(leftBracket, jwhitespace, rightBracket),
_ => ([])
),
map(
and(leftBracket, jelements, rightBracket),
value => (value.slice(1, value.length - 1)).filter(v => v !== ",")
)
),
value => ({ type: "array", value })
);
```

Now we can make a test.

```
const state = createInitState("[1,2,3]");
const ast = jarray(state);
console.log(JSON.stringify(ast, null, 2));
/**
{
"data": "[1,2,3]",
"index": 7,
"error": null,
"value": {
"type": "array",
"value": [
{
"type": "scalar",
"value": 1
},
{
"type": "scalar",
"value": 2
},
{
"type": "scalar",
"value": 3
}
]
}
}
*/
```

En, looks good. But wait, we still have one case hav't not considered: nested arrays.

```
[1,2,[3,[4],[]]]]
```

This is pretty complicated. Actually it is not. We have build a good structure, let's see how to handle it now. Remember we defined a parser `jelement`

to express element in array. And we use `jvalue`

to express `jelement`

. So the possible values types of array is `jvalue`

. We already filled `jvalue`

with strings, numbers, booleans, etc. We can just add `jarray`

parser into it and then we can parse arrays recursively.

```
const jvalue = or(
lazy(() => jarray),
jstring,
jnumber,
jtrue,
jfalse,
jnull
);
```

Now we can handle nested arrays.

```
const state = createInitState("[1,2,[3,[4],[]]]]");
const ast = jarray(state);
console.log(JSON.stringify(ast, null, 2));
/**
{
"data": "[1,2,[3,[4],[]]]]",
"index": 16,
"error": null,
"value": {
"type": "array",
"value": [
{
"type": "scalar",
"value": 1
},
{
"type": "scalar",
"value": 2
},
{
"type": "array",
"value": [
{
"type": "scalar",
"value": 3
},
{
"type": "array",
"value": [
{
"type": "scalar",
"value": 4
}
]
},
{
"type": "array",
"value": []
}
]
}
]
}
}
*/
```

OK, that's good. Let's start to handle the last part of JSON: object.

Object is key value pairs. It can contains multiple entries and can be nested as well just like array.

Let's first define a `member`

parser to express one entry in object.

```
const member = map(
and(
jwhitespace,
jstring,
jwhitespace,
colon,
jelement
),
value => ({ "key": value[1], "value": value[4] })
);
```

As you can see, it can be surrounded by whitespaces as well. The key must be a string and value can be any types.

Next is `members`

parser to express multiple extries in object.

```
const members = or(
and(member, comma, lazy(() => members)),
member
);
```

As you can see, it's structure is very similar to `jelements`

for array.

Then we can define the parser to parse an object. Same thing with array, an object can have 2 cases: empty object and not empty object.

```
const jobject = map(
or(
map(
and(leftCurlyBracket, jwhitespace, rightCurlyBracket),
_ => ({})
),
map(
and(leftCurlyBracket, members, rightCurlyBracket),
value => (value.slice(1, value.length - 1)).filter(v => v !== ",")
)
),
value => ({ type: "object", value })
);
```

And don't forget to add `jobject`

into `jvalue`

to make it handle nested objects.

```
const jvalue = or(
lazy(() => jarray),
lazy(() => jobject),
jstring,
jnumber,
jtrue,
jfalse,
jnull
);
```

Finally, we can define out root JSON parser. A JSON can be one any scalar value or an array or an object. So it is just the `jvalue`

parser. To make it handle whitespaces, we use `jelement`

instead of `jvalue`

directly.

```
const jsonParser = jelement;
```

Now we can make a test again.

```
const state = createInitState(`[1,2,true,{"hello": false, "world": [null]}]`);
const ast = jsonParser(state);
console.log(JSON.stringify(ast, null, 2));
/**
{
"data": "[1,2,true,{\"hello\": false, \"world\": [null]}]",
"index": 44,
"error": null,
"value": {
"type": "array",
"value": [
{
"type": "scalar",
"value": 1
},
{
"type": "scalar",
"value": 2
},
{
"type": "scalar",
"value": true
},
{
"type": "object",
"value": [
{
"key": {
"type": "scalar",
"value": "hello"
},
"value": {
"type": "scalar",
"value": false
}
},
{
"key": {
"type": "scalar",
"value": "world"
},
"value": {
"type": "array",
"value": [
{
"type": "scalar",
"value": null
}
]
}
}
]
}
]
}
}
*/
```

That's not all of it. We still need to evalute this ast to get the final result. Since we already have a well-structured ast, evaluation is very simple.

```
const evaluate = node => {
switch (node.type) {
case "scalar":
return node.value;
case "array":
return node.value.map(value => evaluate(value));
case "object":
return Object.fromEntries(
node.value.map(
value => ([evaluate(value.key), evaluate(value.value)])
)
);
default:
console.error("invalid type", node);
}
};
```

OK, let's make a final test.

```
const result = evaluate(ast.value);
console.log(JSON.stringify(result, null, 2));
/**
[
1,
2,
true,
{
"hello": false,
"world": [
null
]
}
]
*/
```

It works just as expected.

Lastly, I have to say this is not all. Even if JSON is a very clear data format. There are still many edge cases we have not handled like fractions, exponents, special unicode, etc. So please use this code with caution. Good luck!

]]>For example, below is simple parser which can do one simple job: parse the character a.

```
const a = s => {
if (s.startsWith("a")) return true;
else return false;
};
console.log(a("abc")); // true
console.log(a("bc")); // false
```

What about character b or c or others? To make it more general, we can write a function char which can takes in any character and return a parser to parse that character.

```
const char = c => s => {
if (s.startsWith(c)) return true;
else return false;
};
const a = char("a");
const b = char("b");
console.log(a("abc")); // true
console.log(b("bc")); // true
```

OK, it can create parsers to parse any character. But now it only can parse the first character of the input string, we want to specify the start index. And also, if the parsing succeeded, we want the parsing result, not just a boolean value. And if the parsing failed, then we want an error message.

Then, we come up with an object, which contains all the information.

```
function createInitState(data) {
return {
data: data,
index: 0,
error: null,
value: null,
};
}
```

We pass it to the parser and the parser should return the same structure so can pass the result to another parser. So our char function becomes this.

```
const char = c => state => {
if (state.error) return state;
const { index, data } = state;
if (index >= data.length) {
return {
...state,
error: `not enough data to parse, index: ${index}, char: ${c}`
};
}
const value = data.charAt(index);
if (value !== c) {
return {
...state,
error: `parse error, index: ${index}, expect: ${c}, got: ${value}`
};
}
return {
...state,
index: index + 1,
value
};
};
```

OK, now we can parse a string like below.

```
const a = char("a");
const b = char("b");
const c = char("c");
let state = createInitState("abc");
state = a(state);
console.log(state);
// { data: 'abc', index: 1, error: null, value: 'a' }
state = b(state);
console.log(state);
// { data: 'abc', index: 2, error: null, value: 'b' }
state = c(state);
console.log(state);
// { data: 'abc', index: 3, error: null, value: 'c' }
```

As you read this, you may want to ask, yes, it can parse one character, what's the big deal? Well, now comes the parser combinators. A parser combinator is just a function, which accepts parsers as input and output a new parser. You can think that its job is to combine multiple parser together to make a more complicated one.

Let's build our first parser combinator. Instead of one specified character, we want to create a parser which can try mutiple parser, if any of them succeed, then return the result. If none of them succeed, then return an error. It's like the effect of or. Let's start with the most simple or, just takes in two parsers.

```
const _or = (p1, p2) => state => {
if (state.error) return state;
let nextState = p1(state);
if (!nextState.error) return nextState;
nextState = p2(state);
if (!nextState.error) return nextState;
return {
...state,
error: `error or`,
};
};
```

The code is very simple, it just try to use the input parsers as requested. Now we can create a parser to parse one character or another character.

```
const a = char("a");
const b = char("b");
const ab = _or(a, b);
console.log(ab(createInitState("abc")));
// { data: 'abc', index: 1, error: null, value: 'a' }
console.log(ab(createInitState("bc")));
// { data: 'bc', index: 1, error: null, value: 'b' }
```

Now our or function can only takes 2 parsers. Based on this, we can easily make it takes in any number of parsers.

```
const or = (...parsers) => state => {
return parsers.reduce((p1, p2) => _or(p1, p2))(state);
};
```

As you can see, it's so simple. We just need to try one by one. With this new `or`

function, we can create a digit parser, which could parse any digit number.

```
const zero = char("0");
const one = char("1");
const two = char("2");
const three = char("3");
const four = char("4");
const five = char("5");
const six = char("6");
const seven = char("7");
const eight = char("8");
const nine = char("9");
const digit = or(zero, one, two, three, four, five, six, seven, eight, nine);
console.log(digit(createInitState("123")));
console.log(digit(createInitState("23")));
console.log(digit(createInitState("3")));
// { data: '123', index: 1, error: null, value: '1' }
// { data: '23', index: 1, error: null, value: '2' }
// { data: '3', index: 1, error: null, value: '3' }
```

OK, enough with one character, we want to parse more character. Similar to function `or`

, we can create a function `and`

. Its job is to takes in multiple parsers and try to run the parsers one by one. If any of the parsers failed, then we return an error. If all of then succeed, then we return the combined result values.

```
// same thing as _or, we start with 2 parsers input _and
const _and = (p1, p2) => state => {
if (state.error) return state;
let p1State = p1(state);
if (p1State.error) return p1State;
let p2State = p2(p1State);
if (p2State.error) return p2State;
return {
...p2State,
value: [p1State.value, p2State.value]
};
};
// based on _and, we build this general and
const and = (...parsers) => state => {
if (state.error) return state;
const parser = parsers.reduce((p1, p2) => {
return _and(p1, p2);
});
const nextState = parser(state);
if (nextState.error) return nextState;
nextState.value = nextState.value.flat(Infinity);
return nextState;
};
```

With this and function, we can create a parser which could parse any specified string.

```
const h = char("h");
const e = char("e");
const l = char("l");
const o = char("o");
const hello = and(h, e, l, l, o);
console.log(hello(createInitState("hello123")));
// {
// data: 'hello123',
// index: 5,
// error: null,
// value: [ 'h', 'e', 'l', 'l', 'o' ]
// }
```

Let's dig deeper, now we only can create a specified number of characters. We want to create a parser combinator which should parse any number of characters as long as there is no error. For example, we can create a function `many`

, which takes in only one parser. And the returned parser should try to use this one parser to parse the string endlessly until there is an error. It like the meta character `*`

in regular expressions.

```
const many = parser => state => {
if (state.error) return state;
let value = [];
let pre = state;
while (true) {
state = parser(pre);
if (state.error) break;
value.push(state.value);
pre = state;
}
return {
...pre,
error: null,
value
};
};
```

As you can see, with prior experience with `or`

and `and`

, this `many`

should seems easy. It just use a while loop to do the greedy parsing like `*`

.

With this `many`

function, we can create a parser to parse a number, not just one character, a complete number.

```
const digits = many(digit);
console.log(digits(createInitState("123abc")));
// { data: '123abc', index: 3, error: null, value: [ '1', '2', '3' ] }
```

Because the `many`

function could parse empty as well, so with `digits`

we want to ensure there is at least one digit, so we could do this.

```
const digits = and(digit, many(digit))
```

It's like the effect of `+`

in regular expressions. You can create a new parser combinator for this task too.

As you can see, now we can parse a number successfully. But the result value is not good. We want to number `123`

, not an array of `[ '1', '2', '3' ]`

. Yes we can convert the result in the `many`

function, but that is not a good idea. We can create a `map`

function, which takes in a parser and a callback function, and use this callback function to convert the result.

```
const map = (parser, fn) => state => {
if (state.error) return state;
state = parser(state);
if (state.error !== null) return state;
state.value = fn(state.value);
return state;
};
```

Now let's convert result to real numbers.

```
const digits = map(and(digit, many(digit)), value => Number(value.join("")));
console.log(digits(createInitState("123abc")));
// { data: '123abc', index: 3, error: null, value: 123 }
```

Well, these are basics of parser combinators. Let's try to use what we learn to solve some problems. The leetcode problem Ternary Expression Parser is a good example.

A ternary is like a simple version of if else statement. The most simple example is like `"T?2:3"`

. Because `T`

stands for true, so we should return the value 2. Things may become complicated when these expressions can be nested like `F?1:T?4:5`

, or a more complicated one `F?T?F?7:F?F?F?3:F?F?0:1:0:6:1:0:5`

. Now let's see how to solve this problem by parser combinators.

We define some basic elements of this expression first.

```
const T = map(char("T"), value => ({ type: "bool", value }));
const F = map(char("F"), value => ({ type: "bool", value }));
const question = char("?");
const colon = char(":");
const digit = map(
or(zero, one, two, three, four, five, six, seven, eight, nine),
value => ({
type: "digit",
value,
})
);
```

And then the ternary expression's structure should looks like below.

```
const ternary = map(
and(
or(T, F),
question,
or(ternary, digit, T, F),
colon,
or(ternary, digit, T, F),
),
value => {
return {
type: "expression",
value
};
}
);
```

Because the expression is a nested structure, so as you can see, we use a recursive approach to expression this structure.

But if we try to run this, we should get an error.

```
or(ternary, digit, T, F),
^
ReferenceError: Cannot access 'ternary' before initialization
```

The error is obvious, we can't use `ternary`

when initilizing `ternary`

. So one solution is that we can create a `lazy`

function to make this parser combinator do lazy execution.

```
const lazy = thunk => state => thunk()(state);
```

It's very similar to other parser combinators, but in this time, it takes in a thunk function, which is used to return the real parser.

Now we can make a parser combinator runs lazily.

```
lazy(() => or(a, b));
```

As you can see, in this time, even if the `lazy`

function is called immediately, the `or`

function will not be called until passing the `state`

to do the realing parsing job.

So now the `tenary`

parser combinator should looks like below.

```
const ternary = map(
and(
or(T, F),
question,
lazy(() => or(ternary, digit, T, F)),
colon,
lazy(() => or(ternary, digit, T, F)),
),
value => {
return {
type: "expression",
value
};
}
);
```

Now let's use it to parse a ternary expression `F?1:T?4:5`

.

```
var parseTernary = function (expression) {
let state = {
data: expression,
index: 0,
error: null,
value: null,
};
state = ternary(state);
console.log(JSON.stringify(state, null, 2))
};
console.log(parseTernary("F?1:T?4:5"));
/**
{
"data": "F?1:T?4:5",
"index": 9,
"error": null,
"value": {
"type": "expression",
"value": [
{
"type": "bool",
"value": "F"
},
"?",
{
"type": "digit",
"value": "1"
},
":",
{
"type": "expression",
"value": [
{
"type": "bool",
"value": "T"
},
"?",
{
"type": "digit",
"value": "4"
},
":",
{
"type": "digit",
"value": "5"
}
]
}
]
}
}
*/
```

With this parsing result, we can evaluate the result easily.

```
const evaluate = node => {
switch (node.type) {
case "expression":
return evaluate(node.value[0]) === "T" ?
evaluate(node.value[2]) : evaluate(node.value[4]);
default:
return node.value;
}
};
```

Finally, we solve the problem.

```
var parseTernary = function (expression) {
let state = {
data: expression,
index: 0,
error: null,
value: null,
};
state = ternary(state);
return evaluate(state.value);
};
console.log(parseTernary("F?1:T?4:5")); // 4
console.log(parseTernary("F?T?F?7:F?F?F?3:F?F?0:1:0:6:1:0:5")); // 5
```

]]>The process is very similar to the LZW. When we finish this article, we can see what the improvement is.

In LZ78, if current substring is `abc`

and it is not in dictionary, then we will output a tuple with `[dic["ab"], "c"]`

. So the final output of LZ78 algorithm is a list of these tuples. But in LZW algorithm, we only output the `dic["ab"]`

, so the final output is just a list of number like `[1,2,3...]`

.

In LZ78, the dictionary is started as empty and built at the same time with the input data. In LZW, the dictionary is initialized with 0-255 ascii characters and later follow the similar approach with LZ78.

Now let take the same example string `BABAABRRR`

to see how it is encoded and decoded by LZW algorithm.

```
0 1 2 3 4 5 6 7 8
B A B A A B R R R
i => 0:
char: "B", pre: "", cur: "B"
cur in dic, pre = cur, move to next
i => 1:
char: "A", pre: "B", cur: "BA"
cur not in dic,
push pre to output: [dic["B"]]
push cur to dic: {..., "BA": 257}
update pre as char: pre: "A"
i => 2:
char: "B", pre: "A", cur: "AB"
cur not in dic,
push pre to output: [dic["B"], dic["A"]]
push cur to dic: {..., "BA": 257, "AB": 258}
update pre as char: pre: "B"
i => 3:
char: "A", pre: "B", cur: "BA"
cur in dic, pre = cur, move to next
...
```

Note that, after the iteration, the `cur`

substring with the last character may exists in dictionary as well, so don't forget to check this edge case.

Now let see this encoding process in code.

```
function encode(text: string): number[] {
const dic = new Map<string, number>();
for (let i = 0; i < 256; i++) {
dic.set(String.fromCharCode(i), i);
}
let pre = "";
const output: number[] = [];
for (const char of text) {
let cur = pre + char;
if (dic.has(cur)) {
// exist in dictionary, move to next iteration
pre = cur;
} else {
// not exit, push pre to output and dictionary, update pre as char
output.push(dic.get(pre) as number);
dic.set(cur, dic.size);
pre = char;
}
}
if (pre !== "") {
output.push(dic.get(pre) as number);
}
return output;
}
```

Make a test.

```
const text = "BABAABRRR";
const encoded = encode(text);
// [ 66, 65, 256, 257, 82, 260 ]
```

Now let's see the decoding process.

For decoding, we need to iterate the encoded list. For each iteration, we convert current code point into string and push it into output. To update the dictionary, we take the previous code point and the first character of current string, make it the next entry in the dictionary.

One edge case we need to handle. Sometimes we may encouter a code point which is not in current dictionary. For example, if the text is `abababab`

, then encoded result is `[97, 98, 256, 258, 98]`

. Then when decoding at the the code point 258, it is not in the dictionary yet. In this case, we just concat the previous string with the first character of the previous string and push it to the output.

Now let's see this process in code.

```
function decode(encoded: number[]): string {
const dic = new Map<number, string>();
for (let i = 0; i < 256; i++) {
dic.set(i, String.fromCharCode(i));
}
// first value as start
let pre = dic.get(encoded[0]) as string;
let output = pre;
for (let i = 1; i < encoded.length; i++) {
const codePoint = encoded[i]
let cur: string;
if (dic.has(codePoint)) {
// if codePoint exists in dictionary, then use it
cur = dic.get(codePoint) as string;
} else {
// if not, use pre + pre[0];
cur = pre + pre.charAt(0);
}
// push it to output
output += cur;
// new dict entry: pre + cur[0]
dic.set(dic.size, pre + cur.charAt(0));
pre = cur;
}
return output;
}
```

Make a test.

```
const text = "BABAABRRR";
const encoded = encode(text);
const decoded = decode(encoded);
console.log({ text, encoded, decoded });
// { text: "BABAABRRR", encoded: [ 66, 65, 256, 257, 82, 260 ], decoded: "BABAABRRR" }
```

]]>We can follow the description and multiple number x with n times.

```
function myPow(x: number, n: number): number {
// for negative n, we need to do a 1/x operation
if (n < 0) {
n = -1 * n;
x = 1 / x;
}
let ans = 1;
for (let i = 0; i < n; i++) {
ans *= x;
}
return ans;
};
```

As you can see, in this way, the time complexity is `O(n)`

.

We can use a divide and conquer approach to make the time complexity `O(log(n))`

.

The idea behind this algorithm is based on the ideas below.

If number n is even, then we can have:

```
x^n = x^(n/2) * x^(n/2)
```

So with this idea, we can calculate `x^n`

with only `n/2+1`

multiplication operations, instead of `n`

times. (Suppose we do `x^(n/2)`

with the brute-force approach).

If number n is odd, we can just minus 1 to make it even:

```
n = n - 1
x^n = x^(n/2) * x^(n/2) * x
```

So with this simple idea, let's see it in code.

```
function myPow(x: number, n: number): number {
if (n < 0) {
n = -1 * n;
x = 1 / x;
}
if (n === 0) return 1;
if (n % 2 === 0) {
const v = myPow(x, n / 2);
return v * v;
} else {
const v = myPow(x, (n-1) / 2);
return v * v * x;
}
};
```

]]>Remember that in binary tree algorithm, we iterate every cell and choose to break the wall on west or north randomly. For the sidewinder algorithm, we also need to iterate every cell, but with a different way for breaking wall.

For one normal iteration, we also have 2 choices. The first one is to break the wall on the east. Suppose we have broke the walls on the east for 2 consecutive steps. Then we should have a horizontal cube with length of 3 cells. Then we move east for the next cell and flip the coins again. This time we need to take the second choice. The second choice is, choose a cell from the cube randomly, and break the wall on the north. And this time, current cell's east wall is retained.

So only this 2 steps, a little complicated than the binary tree algorithm. Below code snippet should show the process more clearly.

```
// for every step
// break east or choose one to break north
if (Math.random() < 0.5) {
maze[i][j] = [0, 1];
} else {
// choose an index
const index = chooseNorthIndex(start, j);
// break north
maze[i][index][1] = 0;
// retain east
maze[i][j][0] = 1;
// start stands for the start index of the cube
start = j + 1;
}
```

OK, still there are edge cases need to handle. If we are at the first row, we shouldn't break the wall on the north and if we are the the last column, we should break the wall on the east.

So, than's all. Let do it in code.

```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.row {
display: flex;
}
.item {
box-sizing: border-box;
width: 10px;
height: 10px;
}
.item:first-child {
border-left: 1px solid black;
}
.row:last-child .item {
border-bottom: 1px solid black;
}
.east-wall {
border-right: 1px solid black;
}
.north-wall {
border-top: 1px solid black;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
function draw(maze) {
function createItem(state) {
const item = document.createElement("div");
item.classList.add("item");
switch (state[0]) {
case 1:
item.classList.add("east-wall");
break;
case 0:
item.classList.add("east-pass");
break;
}
switch (state[1]) {
case 1:
item.classList.add("north-wall");
break;
case 0:
item.classList.add("north-pass");
break;
}
return item;
}
const container = document.createElement("div");
for (const row of maze) {
const rowEle = document.createElement("div");
rowEle.classList.add("row");
for (const state of row) {
rowEle.appendChild(createItem(state));
}
container.appendChild(rowEle);
}
root.innerHTML = "";
root.appendChild(container);
}
const maze = init(42, 72);
random(maze);
draw(maze);
function init(width, heigth) {
const maze = Array.from({ length: width }, _ => {
// cell states as [x, y]
// x for if east has wall
// y for if north has wall
return Array.from({ length: heigth }, _ => [1, 1]);
});
return maze;
}
function random(maze) {
function chooseNorthIndex(start, current) {
const range = current - start + 1;
const index = Math.floor(Math.random() * range) + start;
return index;
}
for (let i = 0; i < maze.length; i++) {
let start = 0;
for (let j = 0; j < maze[i].length; j++) {
if (i === 0 && j === maze[i].length - 1) {
// northeast, all wall
maze[i][j] = [1, 1];
} else if (i === 0) {
// first row, north wall, east pass
maze[i][j] = [0, 1];
} else if (j === maze[i].length - 1) {
// last column, choose
const index = chooseNorthIndex(start, j);
maze[i][index][1] = 0;
maze[i][j][0] = 1;
start = j + 1;
} else {
// for every step
// move forward or choose break north
if (Math.random() < 0.5) {
maze[i][j] = [0, 1];
} else {
const index = chooseNorthIndex(start, j);
maze[i][index][1] = 0;
maze[i][j][0] = 1;
start = j + 1;
}
}
}
}
}
</script>
</body>
</html>
```

So with this code, we can generate mazes like below.

]]>To generate a maze, we first need to define a table like below.

As you can see, it is a normal table, with rows and columns. We can think each cell as the empty road in a maze and each edges as wall. Currently, there are all walls, we can't move to anywhere. What we will do now is to iterate all the cells of the table. For each iteration, we have 2 choices, either break the wall in the north, or break the wall in the left. We make the choice randomly.

Some special edge cases need to be handled. Say we are at the first row. We can't break the wall in the north now because that will break out the maze. Same thing happens when we are at the first column. So in the first row, we can only choose to break the wall in the west, and in the first column, we can only choose to break the wall in the north. And if we are at the first cell now, we can't do both.

So follow this procedure, let do it in code.

```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.row {
display: flex;
}
.item {
box-sizing: border-box;
width: 10px;
height: 10px;
}
.item:last-child {
border-right: 1px solid black;
}
.row:last-child .item {
border-bottom: 1px solid black;
}
.left-wall {
border-left: 1px solid black;
}
.north-wall {
border-top: 1px solid black;
}
</style>
</head>
<body>
<div id="root"></div>
<script>
function draw(maze) {
function createItem(state) {
const item = document.createElement("div");
item.classList.add("item");
switch (state[0]) {
case 1:
item.classList.add("left-wall");
break;
case 0:
item.classList.add("left-pass");
break;
}
switch (state[1]) {
case 1:
item.classList.add("north-wall");
break;
case 0:
item.classList.add("north-pass");
break;
}
return item;
}
const container = document.createElement("div");
for (const row of maze) {
const rowEle = document.createElement("div");
rowEle.classList.add("row");
for (const state of row) {
rowEle.appendChild(createItem(state));
}
container.appendChild(rowEle);
}
root.innerHTML = "";
root.appendChild(container);
}
function init(width, heigth) {
const maze = Array.from({ length: width }, _ => {
// cell states as [x, y]
// x for if west has wall
// y for if north has wall
return Array.from({ length: heigth }, _ => [1, 1]);
});
return maze;
}
function random(maze) {
for (let i = 0; i < maze.length; i++) {
for (let j = 0; j < maze[i].length; j++) {
if (i === 0 && j === 0) {
maze[i][j] = [1, 1];
} else if (i === 0) {
maze[i][j] = [0, 1];
} else if (j === 0) {
maze[i][j] = [1, 0];
} else {
if (Math.random() < 0.5) {
maze[i][j] = [1, 0];
} else {
maze[i][j] = [0, 1];
}
}
}
}
}
const maze = init(36, 72);
random(maze);
draw(maze);
</script>
</body>
</html>
```

Run the code in the browser, we can generate a random maze like below.

]]>Let's understand what is longest common subsequence first. A subsequence of a string is a new string generated from the original string. It is not required to be consecutive, so `a`

, `ab`

, `ac`

, `ad`

are all subsequence of `abcd`

, as long as the order is the same as the original string. So given 2 strings, the step is find all subsequence for each string, and return longest one.

Of course we could follow the description of the problem to use the brute-force approach to find all subsequences. But this is time-consuming. The key to solve this problem efficiently is to cut current problems into one or many smaller problems, then find the relations between the two.

So, if text1's length is m, and text2's length is n, consider the following 3 smaller problems:

```
current problem: lcs(text1, text2)
smaller problems:
- lcs(text1.slice(0, m-1), text2)
- lcs(text1, text2.slice(0, n-1))
- lcs(text1.slice(0, m-1), text2.slice(0, n-1))
```

What is the relation between current problem with the smaller ones? Well if `text1[m-1]) === text2[n-1])`

, which means the last characters of each string are equal, then because we got 1 character matched, so we can get a relation: `lcs(text1, text2) = 1 + lcs(text1.slice(0, m-1), text2.slice(0, n-1))`

. If the last character are not equal, then we have 2 options. Either delete the last character of text1, or delete the last character of text2, then try to check again. The question is to find the longest common subsequence, so what we want to do is calculate both options and choose the longest one. So we have another pattern: `lcs(text1, text2) = max(lcs(text1.slice(0, m-1), text2), lcs(text1, text2.slice(0, n-1))`

.

With these 2 pattern, we could make current problem into smaller problems. Then do it recursively, until when either string is empty. Let's do it in code.

```
function longestCommonSubsequence(text1: string, text2: string): number {
function lcs(i: number, j: number) {
if (i === text1.length || j === text2.length) return 0;
if (text1[i] === text2[j]) {
return 1 + lcs(i + 1, j + 1);
} else {
return Math.max(lcs(i + 1, j), lcs(i, j + 1))
}
}
return lcs(0, 0);
};
```

The code is clear and simple, but if we run it in leetcode, then we should get a Time Limit Exceeded failure. If we print the parameters of function lcs when it being called, then we should see that this function is called many time with the same parameters. So the problem is, with this recursive approach, we do a lot repetitive calculations.

The most intuitive way to solve this repetition is to use a cache. Whenever we find a same calculation task, then we can return result directly.

```
function longestCommonSubsequence(text1: string, text2: string): number {
const m = Array.from({ length: text1.length + 1 }, _ => {
return Array.from({ length: text2.length + 1 }, _ => -1);
});
function lcs(i: number, j: number): number {
if (m[i][j] !== -1) return m[i][j];
if (i === text1.length || j === text2.length) {
m[i][j] = 0;
return m[i][j];
}
if (text1[i] === text2[j]) {
m[i][j] = 1 + lcs(i + 1, j + 1);
} else {
m[i][j] = Math.max(lcs(i + 1, j), lcs(i, j + 1));
}
return m[i][j];
}
return lcs(0, 0);
};
```

Try this solution in leetcode again, this should work.

Even if we have a cache, store results into cache and check cache many time still causes overhead.

Actually, based on the patterns we already have, we can folllow a bottom-up approach to make this code run faster further.

The idea is to do a reverse thinking. Instead of breaking big problem into smaller problems, we start with smaller problem first and build up to find answers for big problems.

So, start with empty string, we know if either string is empty, then the result is 0. Then based on the same pattern, we make the string longer and longer and store all temperary results in a 2-dimensional array. After we reach the length of 2 strings, then we get the final answer.

```
function longestCommonSubsequence(text1: string, text2: string): number {
const m = Array.from({ length: text1.length + 1 }, _ => {
return Array.from({ length: text2.length + 1 }, _ => -1);
});
for (let i = 0; i <= text1.length; i++) {
m[i][0] = 0;
}
for (let j = 0; j <= text2.length; j++) {
m[0][j] = 0;
}
// use the same pattern, but build up
for (let i = 1; i <= text1.length; i++) {
for (let j = 1; j <= text2.length; j++) {
if (text1[i - 1] === text2[j - 1]) {
m[i][j] = 1 + m[i - 1][j - 1];
} else {
m[i][j] = Math.max(m[i - 1][j], m[i][j - 1]);
}
}
}
return m[text1.length][text2.length];
};
```

Yes, we already solve the problem. But what we have now is just find the length of the longest common subsequence. So how can we find the string? Well, we already have the 2-dimensional array which stores all temporary results, we could start from the end, and follow the same pattern reversely, and get the longest common subsequence.

```
function longestCommonSubsequence(text1: string, text2: string): string {
const m = Array.from({ length: text1.length + 1 }, _ => {
return Array.from({ length: text2.length + 1 }, _ => -1);
});
for (let i = 0; i <= text1.length; i++) {
m[i][0] = 0;
}
for (let j = 0; j <= text2.length; j++) {
m[0][j] = 0;
}
for (let i = 1; i <= text1.length; i++) {
for (let j = 1; j <= text2.length; j++) {
if (text1[i - 1] === text2[j - 1]) {
m[i][j] = 1 + m[i - 1][j - 1];
} else {
m[i][j] = Math.max(m[i - 1][j], m[i][j - 1]);
}
}
}
let x = text1.length;
let y = text2.length;
let lcsv: string[] = [];
while (true) {
if (x <= 0 || y <= 0 || m[x][y] === 0) break;
if (m[x - 1][y] === m[x][y]) {
x -= 1;
} else if (m[x][y - 1] === m[x][y]) {
y -= 1;
} else {
// push the character which affect the lcs's length
lcsv.push(text1[x - 1]);
x -= 1;
y -= 1;
}
}
lcsv.reverse();
return lcsv.join("");
};
```

]]>The basic usage is just pass a pattern as first parameter and a string as second parameter to replace the matched pattern.

```
const s = "abab";
console.log(s.replace("ab", "--")); // --ab
```

By default, only the first match will be replaced. We can use regex `g`

flag to make full replacement.

```
const s = "abab";
console.log(s.replace(/ab/g, "--")); // ----
```

The second parameter can be a function. By default, there are 3 parameters passed into this function: matched substring, matched substring's offset and the original string. The function's return value will be used to replace the matched substring.

```
const s = "ababab";
console.log(s.replace(/ab/, (match, offset, string) => {
console.log(match, offset, string);
return "--";
}));
/**
ab 0 ababab
--abab
*/
```

We could also use the `g`

flag. In this way this function will be called whenever there is a match.

```
const s = "ababab";
console.log(s.replace(/ab/g, (match, offset, string) => {
console.log(match, offset, string);
return "--";
}));
/**
ab 0 ababab
ab 2 ababab
ab 4 ababab
------
*/
```

If the first parameter is a regex and contains groups, then the group values will be as paramters passed to the second parameter function.

```
const s = "Year: 2020, Month: 11, Day: 12";
console.log(s.replace(/(Year: \d+), (Month: \d+), (Day: \d+)/, (match, g1, g2, g3, offset, string) => {
console.log({ match, g1, g2, g3, offset, string });
return "--";
}));
/**
{
match: 'Year: 2020, Month: 11, Day: 12',
g1: 'Year: 2020',
g2: 'Month: 11',
g3: 'Day: 12',
offset: 0,
string: 'Year: 2020, Month: 11, Day: 12'
}
--
*/
```

We could use `$`

to refer to matched groups values easily.

```
const s = "Year: 2020, Month: 11, Day: 12";
console.log(s.replace(/(Year:\s*\d+),\s*(Month:\s*\d+),\s*(Day:\s*\d+)/, "$3, $2, $1"));
// Day: 12, Month: 11, Year: 2020
```

If these groups are named groups, then there is another parameter passed into the second function, which contains all groups information.

```
const s = "Year: 2020, Month: 11, Day: 12";
console.log(
s.replace(
/(?<year>Year: \d+), (?<month>Month: \d+), (?<day>Day: \d+)/,
(match, g1, g2, g3, offset, string, groups) => {
console.log({ year: groups.year, month: groups.month, day: groups.day });
return "--";
}
)
);
/**
{ Year: '2020', Month: '11', Day: '12' }
--
*/
```

We could also use `$`

to refer to matched named group values.

```
const s = "Year: 2020, Month: 11, Day: 12";
console.log(s.replace(/(?<year>Year: \d+), (?<month>Month: \d+), (?<day>Day: \d+)/, "$<day>, $<month>, $<year>"));
// Day: 12, Month: 11, Year: 2020
```

As you saw earlier, we could use `$`

to do some shortcut operations. Actually, there are more. Let's see some of them.

```
const s = "--abc==";
// $& refer to matched substring
console.log(s.replace("abc", "$&def")); // --abcdef==
// $` refer to substring before the matched substring
console.log(s.replace("abc", "$`")); // ----==
// $' refer to substring after the matched substring
console.log(s.replace("abc", "$'")); // --====
// because $ used as a meta character, so we use $$ to refer to normal $ character
console.log(s.replace("abc", "$$")); // --$==
```

]]>Just like LZ77, LZ78 is also created by Abraham Lempel and Jacob Ziv. They published this algorithm in 1978, so its named LZ78.

The key idea of LZ78 is very similar to LZ77, they all try to find if we already saw current data before, if it is, then we replace current data with a reference to the previous data.

Remember in LZ77, when we have current data and try to know if we have saw this before, we use search to do it. We search the data in look-ahead buffer from the search buffer. Well in LZ78, we use a dictionary. Whenever we see data we have not seen before, we store it in a dictionary. So later we can check this dictionary easily.

Now let's take a example to see how it goes.

Say we have a string `BABAABRRR`

. We iterate this string character by character.

So first we get character `B`

. Now the dictionary is empty, so we store this character into dictionary with value 1: `dic.set("B", 1)`

. And we output an array with 2 values: `[0, B]`

. The first value 0 stands for no reference, `B`

stands for the end character of current data.

Then we move to second character `A`

. There is no `A`

in dictionary, so the same step as before: store `A`

in dictionary: `dic.set("A", 2)`

, and output `[0, "A"]`

.

Then we move to third character `B`

. So there is `B`

in dictionary. So we do nothing, move to next character `A`

. So now we have `BA`

, is `BA`

in the dictionary? No. OK, so follow the same process, store `BA`

in dictionary: `dic.set("BA", 3)`

, and this time, we output `[1, "A"]`

. This `1`

is the value of `dic.get("B")`

, stands for the reference to the previous data, and `A`

is current string's last character, stands for new data.

So now you know this basic 2 cases. Let's see all steps in below.

```
0 1 2 3 4 5 6 7 8
B A B A A B R R R
i => 0, cur => B, dic => {"B", 1}, output: [0, "B"]
i => 1, cur => A, dic => {"A", 2}, output: [0, "A"]
i => 2, cur => B
i => 3, cur => BA, dic => {"BA": 3}, output: [1, "A"]
i => 4, cur => A,
i => 5, cur => AB, dic => {"AB": 4}, output: [2, "B"]
i => 6, cur => R, dic => {"R": 5}, output: [0, "R"]
i => 7, cur => R,
i => 8, cur => RR, dic => {"RR": 6}, output: [5, "R"]
```

OK, now we know all the process, let see how to do encoding in code.

```
type Item = [number, string];
function encode(data: string): Item[] {
const dic = new Map<string, number>();
dic.set("", 0);
let encoded: Item[] = [];
let cur = "";
for (let i = 0; i < data.length; i++) {
cur += data[i];
if (dic.has(cur)) {
continue;
};
dic.set(cur, dic.size);
const item: Item = [
// reference previous
dic.get(cur.slice(0, cur.length - 1)) as number,
// output last character
cur[cur.length - 1]
]
encoded.push(item)
cur = "";
}
// handle this edge case
if (cur.length > 0) {
encoded.push([dic.get(cur) as number, ""])
}
return encoded;
}
```

Decoding is a lot easier. The key is follow the same process in reverse, building the dictionary and decoding at the same time.

```
function decode(encoded: Item[]): string {
let decoded = "";
const dic = new Map<number, string>();
dic.set(0, "");
for (const item of encoded) {
const pre = dic.get(item[0]) as string;
decoded += pre;
decoded += item[1];
dic.set(dic.size, pre + item[1]);
}
return decoded;
}
```

You can see how clever this algorithm is. We don't need to store the dictionary, the dictionary is built along with decoding process.

And lastly, we make some tests.

```
function test(data: string) {
const encoded = encode(data);
const decoded = decode(encoded);
console.log({ data, encoded, decoded }, decoded === data)
}
test("ABBCBCABABCAABCAAB")
test("BABAABRRR")
test("AAAAAAAAA")
/**
{
data: "ABBCBCABABCAABCAAB",
encoded: [
[ 0, "A" ],
[ 0, "B" ],
[ 2, "C" ],
[ 3, "A" ],
[ 2, "A" ],
[ 4, "A" ],
[ 6, "B" ]
],
decoded: "ABBCBCABABCAABCAAB"
} true
{
data: "BABAABRRRA",
encoded: [
[ 0, "B" ],
[ 0, "A" ],
[ 1, "A" ],
[ 2, "B" ],
[ 0, "R" ],
[ 5, "R" ],
[ 2, "" ]
],
decoded: "BABAABRRRA"
} true
{
data: "AAAAAAAAA",
encoded: [ [ 0, "A" ], [ 1, "A" ], [ 2, "A" ], [ 3, "" ] ],
decoded: "AAAAAAAAA"
} true
*/
```

]]>```
23958233
5830
00000000 ( = 23,958,233 0)
71874699 ( = 23,958,233 30)
191665864 ( = 23,958,233 800)
+ 119791165 ( = 23,958,233 5,000)
139676498390 ( = 139,676,498,390)
```

It turns out that this kind of operations is not suitable for CPU. There is an algorithm call Russian Peasant Multiplication, which can do multiplication only by shifting and adding operations, which is more suitable for computers. Let's see how it works.

Suppose we want to calculate `a*b`

. We can rewrite this expression into `a*2*b/2`

. So we make `a=a*2`

and `b=b/2`

, and then calculate `a*b`

again. As you can see, in this way, we make `a`

bigger and `b`

smaller. Follow the same process, until we make `b`

as value 1, then we stop. Then the final result is `a`

. Let's see an example.

```
5 * 8 =>
(5*2) * (8/2) =>
(10*2) * (4/2) =>
(20*2) * (2/2) =>
40
```

Another thing we need to consider is that as we divide `b`

by 2, `b`

could become odd number. We can't divide an odd number by 2, so we need to somehow make it even. The most easy way is to subtract 1. So follow this formula: `a*b => a*(b-1) + a`

, we can make `b`

even again.

Before we go to code, last thing you may notice that from above process is that there are still muliplications(`*2`

, `/2`

). But this 2 multiplications can be achieved by bit shifting operations, so we will not do multiplication in code. Check my previous article about bit operations if you are not familar with them.

Now let's implement this algorithm in code.

```
function multiply(x: number, y: number): number {
let res = 0;
// loop until y becomes 1
while (y > 1) {
// check if y becomes odd
if ((y & 1) > 0) {
res += x;
}
// x * 2
x <<= 1;
// y / 2
y >>= 1;
}
return res + x;
}
```

]]>The key idea of LZ77 is to find patterns and reduce redundancies. For example, if we already seen vocabulary `compression`

before, when we see this vocabulary next time, we reduce this repetition and only store reference for it.

Now let's see how this reference works. Say we want to compress a string `abc-abc+abc`

with LZ77. And we are at position of second `abc`

.

```
****-------
43210123456
abc-abc+abc
```

From above diagram, we can see that the string has 2 parts. The first part is with the `*`

, stands for the part we already seen. The second part is with the `-`

, stands for the part we are plan to handle.

Now what we want to do is to start from index 0, try to match the string we already seen. We can tell that the longest match is index `[0,2]`

, matching with index `[4,2]`

, with string value `abc`

. After calculating this information, then we store it into a length-distance pair. We can think of this length-distance pair as an array with 3 element. The first element stores the starting index of the matched string. In this example, it is 4. The second element stores the matched length. In this example it is 3. The third element stores the next character after matching. In this example, it is character `+`

. So with this one calculation, we get an array `[4, 3, "+"]`

.

So, as you can imagine, we start from the start of the data, for every step, we store a length-distance pair. When the iteration finishes, then we get an array of pairs, which is the encoded data.

Another detail I have not cover is that, there are two buffers to limit the matching process. From above example, we try to match the `-`

part with the `*`

part. The first buffer is called search buffer, stands for the length of the `*`

part. The second one is called look-ahead buffer, stands for the length of the `-`

part. To make the matching execute faster, so in LZ77, these 2 parts are limited.

Now let's take another example to see the whole process.

```
data: aacaacabcababac
*: search buffer
-: look-ahead buffer
* * * * * * - - -
6 5 4 3 2 1 0 1 2
a a c aacabcababac [0,0,a]
a a c a acabcababac [1,1,c]
a a c a a c abcababac [3,3,a]
a a c a a c a b c a babac [0,0,b]
aa c a a c a b c a b abac [3,3,a]
aacaac a b c a b a b a c [2,2,c]
```

As you can see, if there is no match, we just store 1 character with a pair. If there is a match, we can store much more information with one pair item.

OK, with all this in mind, let try to write code. First is the encoding part.

```
/**
*
* @param data string
* @param sbl search buffer length
* @param lbl look-ahead buffer length
* @returns encoded items
*/
function encode(data: string, sbl: number, lbl: number): Item[] {
const output: Item[] = [];
let pos = 0;
while (pos < data.length) {
// below double for loop for finding longest match
let offset = 0;
let length = 0;
for (let i = pos - 1; i >= pos - sbl && i >= 0; i--) {
let j = i;
for (j = i; j < pos; j++) {
if (j - i + 1 > lbl) break;
if (data[j] !== data[pos + j - i]) break;
}
if (j - i > length) {
length = j - i;
offset = pos - i;
}
}
const c = pos + length < data.length ? data[pos + length] : "";
output.push([offset, length, c]);
pos += length + 1;
}
return output;
}
```

Next is the decoding part. Decoding is a lot easier. We only need to iterate the encoded data, and try to expand the result.

```
function decode(encoded: Item[]): string {
let output = "";
for (const [offset, length, c] of encoded) {
const start = output.length - offset;
const end = start + length;
output += output.slice(start, end);
output += c;
}
return output;
}
```

Now let's make a test.

```
const data = "aacaacabcababac";
const encoded = encode(data, 6, 3);
const decoded = decode(encoded);
console.log({ data, encoded, decoded }, data === decoded);
/**
{
data: "aacaacabcababac",
encoded: [
[ 0, 0, "a" ],
[ 1, 1, "c" ],
[ 3, 3, "a" ],
[ 0, 0, "b" ],
[ 3, 3, "a" ],
[ 2, 2, "c" ]
],
decoded: "aacaacabcababac"
} true
*/
```

]]>To solve this problem, the first pattern we need to find is how many steps we need to take to make it to the first missing positive value. This may seems impossible to know at first, because we don't know what value in the array. The value may be very big, so we may need to try a lot of numbers. Actually, it is not. Take a look a below examples.

```
[-3,-2,-1,1], first missing positive => 2
[1,2,4,5], first missing positive => 3
[1,2,3,4,5], first missing positive => 6
```

As you can see, because the length of the array limits the options, so the max value of the first missing positive is just `length+1`

. So what we need to do is just iterate from 1 to `length+1`

, and check if current value in the array, then we can get the result.

So, we can write a solution like below.

```
function firstMissingPositive(nums: number[]): number {
nums = nums.filter(num => num > 0);
const nset = new Set(nums);
for (let i = 1; i <= nums.length; i++) {
if (!nset.has(i)) return i;
}
return nums.length + 1;
};
```

The time complexity is `O(n)`

, its acceptable. But it also takes `O(n)`

space complexity. How can we only use constant space to solve this problem? Then its the interesting part comes.

Let's think about again what we want. we want a data structure to tell us if nums from 1 to `length+1`

exists in the original array. In the above code, we use a Set to store this information. Actually, we can use the original nums array to store this information too.

The key idea is, we use the original nums array's index as the key, and nums array's values as the value. For example, if 2 is in the array, then we make the value `nums[2]`

to be negative. If 2 is not in the array, we make the value `nums[2]`

to be positive.

That is clever, we can use this positive and negative to store if a num in the nums array. But why? why should we want do this? What is the merit behind this positive and negative thing? Well, think again. When we use the value of the nums array to store another information, we need to change the value somehow. But at some point, we need to access the original value as well. So, this is the reason. By making values negative, we know the index of the value exist, and later we can convert it back to original value easily.

Besides, there are also 1 thing needs to be noted. How should we handle the original negative values? we need to use negative to tell us some information later, so we need to make them positive first. But if we make them positive, then they will confuse with normal postive values. So to solve this, we can make them all as value 1. And then we handle value 1 independently to solve this confusion.

With all this in mind, then we can come up with this `O(1)`

space solution.

```
function firstMissingPositive(nums: number[]): number {
// handle value 1 first
if (!nums.some(num => num === 1)) return 1;
nums = nums.map(num => num > 0 ? num : 1);
for (let i = 0; i < nums.length; i++) {
const num = Math.abs(nums[i]);
if (num <= 1) continue; // don't care value 1
if (num > nums.length) continue; // don't care big values, beyond answer range
// here, we move left, num => nums[num-1], then we can store length => nums[length-1]
if (nums[num - 1] < 0) continue; // only set negative once
nums[num - 1] *= -1;
}
for (let i = 2; i <= nums.length; i++) {
if (nums[i - 1] > 0) return i;
}
return nums.length + 1;
};
```

This technique is very useful. The key idea is to use the data structure we already have to store another information. If we don't care about original value, then its done. If we do want to access original value later, then we need to find a way to store both of them.

]]>The WebSocket Protocol enables two-way communication between a client and server. It is built upon HTTP protocol and defined in rfc6455.

In this article, let's explore some details about websocket server, and try to implement it based on Node.js http package.

Since there is built-in websocket client in browser, so we use it to test server code. The logic is simple, establish connection, send message hello.

```
const ws = new WebSocket("ws://localhost:1988/ws");
ws.onopen = () => {
console.log("onopen");
ws.send("hello");
};
ws.onerror = e => {
console.error("onerror", e);
};
ws.onclose = e => {
console.log("onclose", e);
};
ws.onmessage = e => {
console.log("receive", e.data);
}
```

To establish a websocket connection, the client should send a http request first. This request is required to provide some special headers. An example header is like below.

```
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Origin: http://example.com
Sec-WebSocket-Version: 13
```

Once the client sends this request, the server should handle it properly.

In node.js, we can write a simple http server like below.

```
const http = require('http');
const server = http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<p>Hello World</p>');
});
server.listen(1988);
```

But we can't handle this websocket handshake request like this, because we want to reuse the same tcp connection after handshake.

Node.js provides a `upgrade`

event to handle cases like this. we can listen to this event then we are able to access the raw tcp connection object to do further operations.

```
server.on('upgrade', (req, socket) => {
// ...
});
```

Then the server should send a response like below to complete this handshake.

```
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol: chat
```

Note that there is a `Sec-WebSocket-Accept`

header, this value is calculate based on the header `Sec-WebSocket-Key`

from request. The calculation process is defined in the protocol, and code is like below.

```
function calculateSWA(swk) {
return crypto
.createHash('sha1')
.update(swk + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 'binary')
.digest('base64');
}
```

Then handshake is completed.

```
server.on('upgrade', (req, socket) => {
console.log("upgrade", req.url);
if (req.headers['upgrade'] !== 'websocket') {
socket.end('HTTP/1.1 400 Bad Request');
return;
}
const swk = req.headers['sec-websocket-key'];
const swa = calculateSWA(swk);
const responseHeaders = [
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
`Sec-WebSocket-Accept: ${swa}`,
].join("\r\n") + "\r\n\r\n";
socket.write(responseHeaders);
});
```

After handshake, the websocket connection is established. The next step is to send/receive message between client and server.

```
// recieve data
socket.on('data', buffer => {
// send data
socket.write("...");
});
```

According to the websocket protocol, data format is like below.

```
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
```

So first thing is to parse this data to get the payload data.

You can check the meaning of each fields from the protocol. I will not repeat in here. The parsing code is below.

```
function recvMsg(buffer) {
let offset = 0;
const FIN = (buffer[offset] >> 7) & 1;
console.log({ FIN });
const Opcode = buffer[offset] & 0b1111;
console.log({ Opcode });
switch (Opcode) {
case 0x0:
console.log("continuation frame");
break;
case 0x1:
console.log("text frame");
break;
case 0x2:
console.log("binary frame");
break;
case 0x8:
console.log("connection close");
break;
case 0x9:
console.log("ping");
break;
case 0xA:
console.log("pong");
break;
default:
console.log("invalid Opcode: ", Opcode);
}
offset += 1;
const Mask = (buffer[offset] >> 7) & 1;
console.log({ Mask });
// 7 bits
let PayloadLength = buffer[offset] & 0b01111111;
offset += 1;
// next 16 bits
if (PayloadLength === 126) {
PayloadLength = buffer.readUInt16BE(offset);
offset += 2;
}
// next 64 bits
if (PayloadLength === 127) {
// ...
offset += 8;
}
console.log({ PayloadLength });
const MaskingKey = buffer.subarray(offset, offset + 4);
console.log({ MaskingKey });
offset += 4;
const PayloadData = buffer.subarray(offset);
console.log({ PayloadData }, PayloadData.length);
let message;
if (Mask > 0) {
message = unmask(MaskingKey, PayloadData).toString();
} else {
message = PayloadData.toString();
}
return message;
}
```

One thing needed to be noted is that data can be masked according to the `Mask`

field. If the data is masked, we need to unmask it. The key idea of unmasking is to use xor operations between `MaskingKey`

and `PayloadData`

, its logic is like below.

```
function unmask(MaskingKey, PayloadData) {
for (let i = 0; i < PayloadData.length; i++) {
PayloadData[i] = MaskingKey[i % 4] ^ PayloadData[i];
}
return PayloadData;
}
```

After receiving message, we also want to send message to the client. Because the data format is the same, we only need to construct it according to the format. It's simpler than parsing.

```
function sendMsg(message) {
const PayloadData = Buffer.from(message);
// todo: handle message bigger than length 125
const header = Buffer.from([0b10000001, PayloadData.length]);
const buffer = Buffer.concat([header, PayloadData]);
return buffer;
}
```

OK, now we can send/receive messages.

```
socket.on('data', buffer => {
const message = recvMsg(buffer);
console.log("receive: ", message);
const msgBuffer = sendMsg("World");
socket.write(msgBuffer);
});
```

With all above code, we implement the handshake and messaging in websocket protocol. Although these 2 part are the key of the protocol, since this is a pretty complicated protocol, there are still many contents needed to be considered. Check the protocol by yourself if you're interested. Below I share the whole server code in case if you want to run by yourself.

```
const http = require('http');
const crypto = require('crypto');
function calculateSWA(swk) {
return crypto
.createHash('sha1')
.update(swk + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11', 'binary')
.digest('base64');
}
const server = http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
res.end('<p>Hello World</p>');
});
server.on('upgrade', (req, socket) => {
console.log("upgrade", req.url);
if (req.headers['upgrade'] !== 'websocket') {
socket.end('HTTP/1.1 400 Bad Request');
return;
}
const swk = req.headers['sec-websocket-key'];
const swa = calculateSWA(swk);
const responseHeaders = [
'HTTP/1.1 101 Switching Protocols',
'Upgrade: websocket',
'Connection: Upgrade',
`Sec-WebSocket-Accept: ${swa}`,
].join("\r\n") + "\r\n\r\n";
socket.write(responseHeaders);
socket.on('data', buffer => {
const message = recvMsg(buffer);
console.log("receive: ", message);
const msgBuffer = sendMsg("World");
socket.write(msgBuffer);
});
});
function recvMsg(buffer) {
let offset = 0;
const FIN = (buffer[offset] >> 7) & 1;
console.log({ FIN });
const Opcode = buffer[offset] & 0b1111;
console.log({ Opcode });
switch (Opcode) {
case 0x0:
console.log("continuation frame");
break;
case 0x1:
console.log("text frame");
break;
case 0x2:
console.log("binary frame");
break;
case 0x8:
console.log("connection close");
break;
case 0x9:
console.log("ping");
break;
case 0xA:
console.log("pong");
break;
default:
console.log("invalid Opcode: ", Opcode);
}
offset += 1;
const Mask = (buffer[offset] >> 7) & 1;
console.log({ Mask });
// 7 bits
let PayloadLength = buffer[offset] & 0b01111111;
offset += 1;
// next 16 bits
if (PayloadLength === 126) {
PayloadLength = buffer.readUInt16BE(offset);
offset += 2;
}
// next 64 bits
if (PayloadLength === 127) {
// ...
offset += 8;
}
console.log({ PayloadLength });
const MaskingKey = buffer.subarray(offset, offset + 4);
console.log({ MaskingKey });
offset += 4;
const PayloadData = buffer.subarray(offset);
console.log({ PayloadData }, PayloadData.length);
let message;
if (Mask > 0) {
message = unmask(MaskingKey, PayloadData).toString();
} else {
message = PayloadData.toString();
}
return message;
}
function unmask(MaskingKey, PayloadData) {
for (let i = 0; i < PayloadData.length; i++) {
PayloadData[i] = MaskingKey[i % 4] ^ PayloadData[i];
}
return PayloadData;
}
function sendMsg(message) {
const PayloadData = Buffer.from(message);
// todo: handle message bigger than length 125
const header = Buffer.from([0b10000001, PayloadData.length]);
const buffer = Buffer.concat([header, PayloadData]);
return buffer;
}
server.listen(1988);
```

]]>Symbol is a built-in object and considered as a primitive type like numbers, booleans, etc.

Everytime we call the `Symbol()`

function, we get a value which is guaranteed to be unique.

```
let v1 = Symbol();
let v2 = Symbol();
console.log(v1 === v2); // false
```

There is a special type of symbols call well-known symbols, which is used to customize object behaviors.

Before symbols, if we want customize how to convert object to string, we can define the `toString`

method. Same logic, if we want to customize how to convert object to JSON, we can define the `toJSON`

method. This approach is not ideal, because these method is no different to normal methods. If we want to add more control, we add a new method `toXXX`

, then this method may be the same with your normal methods, then comes the problem.

Now with symbol, because it is guranteed to be unique, so it is suitable for this kind of usage. Now let explore some of them to see how to use them.

Customize how to convert object to string.

```
const obj1 = {
x: 100,
y: 200,
}
console.log(String(obj1)) // [object Object]
const obj2 = {
x: 100,
y: 200,
toString() {
return this.x + "-" + this.y
}
}
console.log(String(obj2)) // 100-200
const obj3 = {
x: 100,
y: 200,
get [Symbol.toStringTag]() {
return this.x + "-" + this.y
}
}
console.log(String(obj3)) // [object 100-200]
```

Make the object iterable.

```
let range = {
from: 1,
to: 10,
[Symbol.iterator]() {
let current = this.from
, last = this.to;
return {
next() {
return (current <= last)
? { done: false, value: current++ }
: { done: true };
}
};
}
};
for (let num of range) {
console.log(num); // 1, 2, 3, 4, 5, ...
}
```

Customize how to convert object to primitive values.

```
let obj = {
value: 100,
[Symbol.toPrimitive](hint) {
if (hint === 'number') return +this.value;
if (hint === 'string') return "value: " + this.value.toString();
return this.value.toString();
}
};
console.log(+obj); // 100
console.log(`${obj}`); // value: 100
```

Note that there is a hint parameter which is used to know what should the target primitive type is.

Customize split function.

```
let obj = {
[Symbol.split](value) {
return value.split("_").filter(v => /\d/.test(v))
}
}
console.log("1_2_3_a_5".split(obj))
// [ '1', '2', '3', '5' ]
```

Same logic goes with `Symbol.match`

, `Symbol.replace`

, `Symbol.search`

.

The rail fence cipher (also called a zigzag cipher) is a classical type of transposition cipher. The process is simple, we put data into a fence-like table with a special format and take them out with with another format, then we can make data encoded.

Below table I take from wiki shows how to put `WE ARE DISCOVERED. RUN AT ONCE.'`

into a table.

```
W . . . E . . . C . . . R . . . U . . . O . . .
. E . R . D . S . O . E . E . R . N . T . N . E
. . A . . . I . . . V . . . D . . . A . . . C .
```

And then, we read data row by row to get an encoded data `WECRUO ERDSOEERNTNE AIVDAC`

.

Now we understand its process, let's see how to code this.

The leetcode Zigzag Conversion is very similar to rail fence cipher, let's use it to see how to implement it in code.

The idea of this method is to find the relation between the index from the row table and the index of characters.

Take string `a-v`

as an example.

```
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
a b c d e f g h i j k l m n o p q r s t u v
0 a i q
1 b h j p r
2 c g k o s
3 d f l n t v
4 e m u
```

Suppose we try to iterate row by row the find the exact index of the character. Code logic like below.

```
let result = "";
for (let i = 0; i < numRows; i++) {
const sIndex = x; // try to find index of string
result += s[sIndex];
}
```

Ignore the inner pattern, try to consider below table first.

```
0 a i q
1 b j r
2 c k s
3 d l t
4 e m u
```

This seems a lot easy. For the first row, we know that we can get result `aiq`

, which has index `0, 8, 16`

in the string. For second row, we can get `bjr`

with index in string as `1, 9, 17`

. For third row, we can get `cks`

with index in string as `2, 10, 18`

. Can you see the pattern here? The cycle length is alway value 8, ex: `8-0, 16-8, 9-1...`

. This value is related with the number of rows and we can easily find the formula `cycleLen = 2*numRows - 2`

.

OK, now let's consider the inner pattern.

```
0 a i q
1 b h j p r
2 c g k o s
3 d f l n t v
4 e m u
only inner part =>
0
1 h p
2 g o
3 f n v
4
```

First thing we can see here is that if the current row's index is equal to 0 or `numRows-1`

, then there is no inner pattern. Second, take a look at the row with index `1`

, it has value `bhjpr`

and inner value `hp`

. We can see that character `h`

just 1 step before next normal pattern value `j`

. For row with index `2`

, it has value `cgkos`

and inner value `go`

. We can see that character `g`

just 2 step before next normal pattern value `k`

. So we find another formula `j + cycleLen - curRowIndex`

, `j`

is the value we found in normal pattern.

So with these 2 part, we can come up a solution.

```
function convert(s: string, numRows: number): string {
if (numRows === 1) return s;
let result: string[] = [];
const cycleLen = 2 * numRows - 2;
// i => rowIndex
for (let i = 0; i < numRows; i++) {
// j => start step
let j = 0;
while (true) {
const si1 = j + i;
if (si1 >= s.length) break;
result.push(s[si1]);
if (i !== 0 && i !== numRows - 1) {
const si2 = j + cycleLen - i;
if (si2 < s.length) {
result.push(s[si2]);
}
}
j += cycleLen;
}
}
return result.join("");
};
```

This method is easier than the first one. We just init an array to simulate the row table. And when we iterate the string, we put characters into correct rows. At the end, we join them back together.

```
function convert(s: string, numRows: number): string {
if (numRows === 1) return s;
const rows = Array.from({ length: numRows }, _ => "");
let curRow = 0;
let goDown = false;
for (const char of s) {
rows[curRow] += char;
if (curRow === 0 || curRow === numRows - 1) {
goDown = !goDown;
}
if (goDown) {
curRow += 1;
} else {
curRow -= 1;
}
}
return rows.reduce((pre, cur) => pre + cur);
};
```

]]>According to Wiki, the method was invented by John von Neumann, and was described at a conference in 1949.

So this is a pretty primitive pseudorandom generator algorithm. But it is also a good starting point for learning how to generate pseudorandom numbers by hand.

The Algorithm's process is very simple. The input is just a number, called the seed, which is used as the starting point. And then we do a square of the seed, and slice the middle part. This is the output and we also use this output for generate next random number.

Below image I take from Wiki shows the process very well.

One thing needed to be considered is that if the number of digit of the seed is odd, then we need to make it even. For example, if the number of digit of the seed is 3, then after square, digits number becomes 6(max). Then we can't slice 3 digits in the middle, because either way digits number of left or right part is not equal.

Below is the simple code demo of this algorithm.

```
class RandomGenerator {
private n: number;
private seed: number;
constructor(seed: number) {
this.seed = seed;
let n = seed.toString().length;
if (n % 2 === 1) {
n += 1;
}
this.n = n;
}
random() {
let vStr = (this.seed * this.seed)
.toString()
.padStart(this.n, "0")
.slice(this.n / 2, this.n / 2 + this.n);
this.seed = parseInt(vStr);
return this.seed;
}
}
const rg = new RandomGenerator(1234);
for(let i = 0; i < 20; i++) {
console.log(rg.random())
}
```

]]>Today I saw another solution, which I think is pretty clever.

The solution is called swapping backtrack. It's process is well explained in below image(which I take from leetcode).

As you can see in the image, there are 2 loops and the second loop starts from the index of the current one.(In above, index `i`

starts from index `first`

). Whenever we find these 2 index is not equal, we do a swapping.

The most easy way to implement it is to do it recursively. Whenever we find index `i`

is equal to index `first`

, then we find one permutation. If its not equal, then we walk to next level.

```
function permute(nums: number[]): number[][] {
let q: number[][] = [];
function backtrack(first: number) {
if (first === nums.length) {
q.push([...nums]);
} else {
backtrack(first + 1);
const v = nums[first];
for (let i = first + 1; i < nums.length; i++) {
// swapping
nums[first] = nums[i];
nums[i] = v;
backtrack(first + 1);
// swapping back
nums[i] = nums[first];
nums[first] = v;
}
}
}
backtrack(0);
return q;
};
```

We can also implement the same logic iteratively. The key that we don't walk down for each loop, we walk to the next value. You can think of the process is a level traversal. So after current level, remember to delete the previous level results.

```
function permute(nums: number[]): number[][] {
let q: number[][] = [nums];
const n = nums.length;
for (let first = 0; first < n; first++) {
let length = q.length;
for (let j = 0; j < length; j++) {
nums = q[j];
const v = nums[first];
q.push([...nums]);
for (let i = first + 1; i < n; i++) {
nums[first] = nums[i];
nums[i] = v;
q.push([...nums]);
nums[i] = nums[first];
nums[first] = v;
}
}
q = q.slice(length);
}
return q;
};
```

]]>The first step is to find a suitable docker image, I found dperson/samba, which is the mostly downloaded one.

If you follow the documentation to run command below, you can't connect to it.

```
sudo docker run -it -p 139:139 -p 445:445 -d dperson/samba -p
```

Then I search the project's repo, and found this issue Can't access shared folders, which is exact the same thing I encountered. The reason is that MacOS does not allow smb connections to "local" shares, e.g. 127.0.0.1. To solve the issue, we need to make an alias to the loopback address, and use the alias for port bindings.

```
sudo ifconfig lo0 127.0.0.2 alias up
```

```
--expose 139 -p 127.0.0.2:139:139 \
--expose 445 -p 127.0.0.2:445:445
```

So the working command is like below.

```
docker run -it -d --name samba \
-p 127.0.0.2:139:139 \
-p 127.0.0.2:445:445 \
dperson/samba \
-s "share;/share;yes;no;no;all;none;${USER};comment" \
-u "${USER};password" \
-p
```

The `-u "${USER};password"`

set up the username and password for Samba server. The `-s "share;/share;yes;no;no;all;none;${USER};comment"`

set up share folder configurations. It follows the format of `-s "<name;/path>[;browse;readonly;guest;users;admins;writelist;comment]"`

. And don't forget the last `-p`

paramter, which is used to config permission according to the project's document.

So with this commnad, we can start a Samba server with share fold `/share`

.

And lastly we can access this folder on Mac with the step: `Finder`

> `Go`

> `Connect to Server...`

> `smb://127.0.0.2`

> `Connect`

.

Node.js provides 2 lower level functions for spawning child processes:

`child_process.spawn()`

`child_process.spawnSync()`

As you can see in its name, the first one is for async operaitions and second one is for synchronous operations.

A few high level apis built upon these 2 low level api, which you can see in below list:

`child_process.spawn()`

`child_process.exec()`

`child_process.execFile()`

`child_process.fork()`

`child_process.spawnSync()`

`child_process.execSync()`

`child_process.execFileSync()`

Now let's see these apis one by one.

Function exec will create a shell then excutes the command passed in. Then we can get the command output from callback function.

```
const child_process = require("child_process");
child_process.exec("ls -l", function (error, stdout, stderr) {
if (error) {
console.error(error.toString());
} else if (stderr !== "") {
console.error(stderr);
} else {
console.log(stdout);
}
});
```

A few options can be passed in. For example, below we pass a signal to abort the subprocess.

```
const controller = new AbortController();
const { signal } = controller;
const child = exec('grep ssh', { signal }, (error) => {
console.log(error); // an AbortError
});
controller.abort();
```

The main difference is between execFile and exec is that, execFile will not spawn a shell by default. Rather, the specified executable file is spawned directly as a new process making it slightly more efficient than exec.

```
child_process.execFile(
"ls",
["-l", "/"],
function (error, stdout, stderr) { }
);
```

The method fork is used specifically to spawn a new Node.js processes.

After new Node.js process created, an IPC communication channel is established, which allows communications between them.

Below example show how to send/receive messages between main process and subprocess.

```
// index.js
const child_process = require("child_process");
const child = child_process.fork(
__dirname + "/child.js", // js file
["-foo"], // pass in paramters
{
env: { bar: "baz" } // env
}
);
child.on("message", function (message) {
console.log("parent received: " + message.count);
if (child.connected) {
message.count++;
child.send(message);
}
});
child.send({ count: 0 });
```

```
// child.js
console.log("argv: " + process.argv);
console.log("env: " + JSON.stringify(process.env, null, 2));
process.on("message", function (message) {
console.log("child received: " + message.count);
if (process.connected) {
message.count++;
process.send(message);
}
});
```

Now comes the function spawn, which is the low level api, and all above 3 apis calls spawn internally.

Below example shows the basic usage of spawn.

```
const child_process = require("child_process");
const ls = child_process.spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', (data) => {
console.log(`stdout: ${data}`);
});
ls.stderr.on('data', (data) => {
console.error(`stderr: ${data}`);
});
ls.on('close', (code) => {
console.log(`child process exited with code ${code}`);
});
ls.on('error', err => {
console.error(err);
});
```

A lot of options can be used in `spawn`

function, but one option called `stdio`

is important to be noted.

Option `stdio`

is usd to configure the comunication between parent and child processes. By default, child process's stdin, stdout and stderr are redirected to corresponding `subprocess.stdin/stdout/stderr`

event, which you can see in above example. If you set option `stdio`

as value `ipc`

, then an IPC channel will created for parent/child communication, which you already seen in `fork`

function example.

Normally, there are 4 methods can be used to create a Buffer.

First one is `Buffer.alloc(size[, fill[, encoding]])`

.

```
const buf1 = Buffer.alloc(5);
console.log(buf1); // <Buffer 00 00 00 00 00>
const buf2 = Buffer.alloc(5, "abc")
console.log(buf2) // <Buffer 61 62 63 61 62>
const buf3 = Buffer.alloc(11, 'aGVsbG8gd29ybGQ=', 'base64');
console.log(buf3) // <Buffer 68 65 6c 6c 6f 20 77 6f 72 6c 64>
```

Second one is `Buffer.allocUnsafe(size)`

.

Buffer created by `allocUnsafe`

is not initialized like `alloc`

, so it may contains arbitrary data.

```
const buf = Buffer.allocUnsafe(5);
console.log(buf); // <Buffer 08 68 05 05 01>
```

Third one is `Buffer.allocUnsafeSlow(size)`

.

This method is similiar to `allocUnsafe`

. The difference is that small buffer(<4KB) create by `allocUnsafe`

is sliced from a single pre-allocated Buffer, and `allocUnsafeSlow`

ensures that all created buffers are new created from operate system.

Fourth one is `Buffer.from`

.

This method is useful for creating buffer from other objects.

```
const buf1 = Buffer.from([1, 2, 3]);
console.log(buf1); // <Buffer 01 02 03>
const buf2 = Buffer.from("haha");
console.log(buf2); // <Buffer 68 61 68 61>
```

We can use `toString`

method to read String from Buffer.

```
const buf1 = Buffer.from("abcdef");
console.log(buf1.toString()); // abcdef
console.log(buf1.toString("hex")); // 616263646566
console.log(buf1.toString("hex", 0, 3)); // 616263
```

We can use `write(string[, offset[, length]][, encoding])`

method to write String into Buffer.

```
const buf = Buffer.alloc(256);
const len = buf.write('\u00bd + \u00bc = \u00be', 0);
console.log(`${len} bytes: ${buf.toString('utf8', 0, len)}`);
// 12 bytes: + =
```

Node.js provides a list of methods for reading/writing number from/into Buffer.

```
const buf = Buffer.alloc(10);
buf.writeUInt8(1, 0);
console.log(buf); // <Buffer 01 00 00 00 00 00 00 00 00 00>
buf.writeUInt8(2, 1);
console.log(buf); // <Buffer 01 02 00 00 00 00 00 00 00 00>
console.log(buf.readUInt16BE(0)); // 258
console.log(buf.readUInt16LE(0)); // 513
```

There are also a list of methods for operations between buffers.

```
// subarray
const buf1 = Buffer.from([1, 2, 3, 4]);
console.log(buf1.subarray(1, 3));
// copy
const buf2 = Buffer.from([6, 7, 8, 9]);
// copy buf1[1:3) to buf2[0:]
buf1.copy(buf2, 0, 1, 3);
console.log(buf2); // <Buffer 02 03 08 09>
// concat
const buf3 = Buffer.concat([buf1, buf2]);
console.log(buf3); // <Buffer 01 02 03 04 02 03 08 09>
// equals
console.log(Buffer.from([1,2,3]).equals(Buffer.from([1,2,3]))) // true
```

TypedArray is the binary standard in JavaScript.

If we have a Buffer, we can pass it to the TypedArray's constructor to create a TypedArray.

```
const buf = Buffer.from([1, 2, 3, 4]);
const uint32array = new Uint32Array(buf);
console.log(uint32array); // [ 1, 2, 3, 4 ]
```

In this way, same size memory is copied, every element in the Buffer should be interpreted as an element in the TypedArray.

We can also pass Buffer's original buffer into TypedArray directly. In this way, TypedArray and Buffer should share the same memory, and TypedArray will interpret elements according to the buffer's content directly.

```
const Uint32Array2 = new Uint32Array(
buf.buffer,
buf.byteOffset,
buf.length / Uint32Array.BYTES_PER_ELEMENT);
console.log(Uint32Array2) // [ 67305985 ]
```

The same logic goes to conversion from TypedArray to Buffer. If we pass TypedArray to Buffer directly, then memory is copied. If we pass its original buffer to Buffer, then they should share the same memory.

```
const arr = new Uint32Array(2);
console.log(arr) // Uint32Array(2) [ 0, 0 ]
// memory copied
const buf1 = Buffer.from(arr)
console.log(buf1) // <Buffer 00 00>
// memory shared
const buf2 = Buffer.from(arr.buffer)
console.log(buf2) // <Buffer 00 00 00 00 00 00 00 00>
```

]]>Below example shows the basic usage of readable stream and writeable stream.

```
const fs = require("fs");
const filePath = "./hello.txt";
const writeStream = fs.createWriteStream(filePath);
writeStream.write("hello,");
writeStream.write("world.");
const readStream = fs.createReadStream(filePath);
readStream.on("data", (data) => {
console.log("read: ", data.toString());
});
readStream.on("close", () => {
console.log("read close");
});
```

We can use different source for readable stream. Below example shows how to create our own stream source.

```
const { Readable } = require("stream");
async function* generate() {
yield "Hello";
yield "World";
}
const rs = Readable.from(generate());
rs.on("data", data => {
console.log(data);
});
```

Instead of data event, we can use promise api to read too.

```
const fs = require("fs");
const rs = fs.createReadStream("hello.txt");
(async () => {
for await (const chunk of rs) {
console.log("read: ", chunk.toString());
}
console.log("close");
})();
```

Readable streams effectively operate in one of two modes: flowing and paused. The difference is:

- In flowing mode, data is read automatically and provided to the user
- In paused mode, the
`stream.read()`

method should be called to read data

By default, a readable stream is in paused mode. We can register a `data`

event or use `pipe`

method to switch to flowing mode like below example.

```
const fs = require("fs");
const rs = fs.createReadStream("./hello.txt");
rs.pipe(process.stdout)
```

Below example shows how to read data manually in paused mode.

```
const fs = require("fs");
const rs = fs.createReadStream("./hello.txt");
rs.on("readable", () => {
let data = rs.read();
while (data !== null) {
console.log("read: ", data.toString());
data = rs.read();
}
});
```

Transform stream could accept a stream, do some transformations then pass it to another stream.

Blow example shows how to pipe a readable stream to a transform stream and then pipe it to a writeable stream.

```
const fs = require("fs");
const { Transform } = require("stream");
const rs = fs.createReadStream("./hello.txt");
const ws = fs.createWriteStream("./world.txt");
const ts = new Transform({
transform(chunk, encoding, callback) {
const changed = chunk.toString().toUpperCase();
callback(null, changed);
}
});
rs.pipe(ts).pipe(ws);
```

Transform stream is very useful. Below example shows how to use it to gzip a file.

```
const fs = require("fs");
const zlib = require("zlib");
const gzip = zlib.createGzip();
const input = fs.createReadStream("hello.txt");
const output = fs.createWriteStream("hello.txt.gz");
input.pipe(gzip).pipe(output);
```

Pipeline is a tool to put multiple stream piping together.

Below example shows the usage of transform stream in a pipeline.

```
const fs = require("fs");
const { Transform, pipeline } = require("stream");
const rs = fs.createReadStream("./hello.txt");
const ws = fs.createWriteStream("./world.txt");
const ts = new Transform({
transform(chunk, encoding, callback) {
const changed = chunk.toString().toUpperCase();
callback(null, changed);
}
});
pipeline(
rs,
ts,
ws,
err => {
if (err) {
console.error(err)
} else {
console.log("pipeline succeeed")
}
}
)
```

There is also a pipeline promise version we can use.

```
const fs = require("fs");
const { Transform, pipeline } = require("stream");
const util = require("util");
const rs = fs.createReadStream("./hello.txt");
const ws = fs.createWriteStream("./world.txt");
const ts = new Transform({
transform(chunk, encoding, callback) {
const changed = chunk.toString().toUpperCase();
callback(null, changed);
}
});
(async () => {
try {
await util.promisify(pipeline)(
rs, ts, ws
);
console.log("success");
} catch (e) {
console.error(e);
}
})();
```

]]>In AVL tree, we calculate each node's height, and use it to decide if rebalance operations are needed and also to decide which rebalance operations to take. In red black tree, we don't need to calculate the height, but we label each node as red or black, and use this label to decide if rebalance operations are needed and which rebalance operations to take. Now let's dig into the details.

First, let see the node structure.

```
class RedBlackNode {
data: number;
left: RedBlackNode | null;
right: RedBlackNode | null;
parent: RedBlackNode | null;
isRed: boolean;
isLeft: boolean;
constructor(data: number) {
this.data = data;
this.left = null;
this.right = null;
this.parent = null;
this.isRed = true; // new node are red
this.isLeft = true; // this will be updated when inserting
}
};
```

As you can see, 3 attributes are added. Attribute parent is used to store current node's parent. Attribute isRed is used to lable the node. Attribute isLeft indicates if current node is left child or right child.

Then comes the insert operation, this is pretty standard.

```
insert(data: number) {
const node = new RedBlackNode(data);
if (this.root === null) {
this.root = node;
} else {
this._insert(this.root, node);
}
this._rebalance(node);
}
private _insert(parent: RedBlackNode, node: RedBlackNode) {
if (node.data < parent.data) {
if (parent.left === null) {
node.isLeft = true;
node.parent = parent;
parent.left = node;
} else {
this._insert(parent.left, node);
}
} else {
if (parent.right === null) {
node.isLeft = false;
node.parent = parent;
parent.right = node;
} else {
this._insert(parent.right, node);
}
}
}
```

Two things needed to be noted here. First is that when we insert a node, we need to set the ifLeft and parent attributes properly. Second, when the node is inserted into the tree, we call the _rebalance function to rebalance the tree.

Now comes the rebalance part. On which conditions should we do the rebalance operations? Actually, there are only 3 steps:

- if current node is the root node, then make node as black
- if current node is red, and its parent is also red, then do rebalance operations
- do first 2 steps recursively

So in code, process is like this.

```
private _rebalance(node: RedBlackNode) {
if (node.parent === null) {
node.isRed = false;
return;
}
if (node.isRed && node.parent.isRed && node.parent.parent !== null) {
// ....
}
this._rebalance(node.parent);
}
```

The rebalance operations include 2 parts in red black tree: rotation and color flipping. Rotation part is almost the same to AVL tree, except for handling the new attributes(parent, isLeft, isRed). Color flopping is an operation to change node's label(red or black).

We need to know current node's aunt's label, then we can decide which operations to take. For example, if current node is d, then its aunt is b.

```
/**
* a
* b c
* d
*
* d is node, b is aunt
*/
```

Then let's see this code flow.

```
let aunt: RedBlackNode | null = null;
if (node.parent.isLeft) {
aunt = node.parent.parent.right;
} else {
aunt = node.parent.parent.left;
}
// operations according to aunt
if (aunt === null || !aunt.isRed) {
this._rotate(node);
} else {
// color flip
// parent => black
// grandparent => red
// aunt => black
if (aunt !== null) {
aunt.isRed = false;
}
node.parent.parent.isRed = true;
node.parent.isRed = true;
}
```

Next is the rotation part. We know that in AVL tree, there are 4 types of rotations, same things for red black tree. But apart from that, there 1 more thing needed to be noted: after rotation, a color flipping operation is needed.

```
private _rotate(c: RedBlackNode): void {
const b = c.parent;
if (b === null) return;
const a = b.parent;
if (a === null) return;
if (c.isLeft) {
if (b.isLeft) {
/**
* a
* b
* c
*
* c is the node
*
* after rotation, tree becomes
*
* b
* c a
*
* make c and a red, b black
*/
this._rightRotate(a);
this._flipColor(b, c, a);
} else {
/**
* a
* b
* c
*
* c is the node
*
* right rotate by b
*
* a
* c
* b
*
* left rotate by a
*
* c
* a b
*
* make a and b red, c black
*
*/
this._rightRotate(b);
this._leftRotate(a);
this._flipColor(c, a, b);
}
} else {
if (!b.isLeft) {
/**
* a
* b
* c
*
* c is the node
*
* after rotation, tree becomes
*
* b
* a c
*
* make a and c red, b black
*/
this._leftRotate(a);
this._flipColor(b, a, c);
} else {
/**
* a
* b
* c
*
* c is the node
*
* left rotate by b
*
* a
* c
* b
*
* right rotate by a
*
* c
* b a
*
* make b and a red, c black
*/
this._leftRotate(b);
this._rightRotate(a);
this._flipColor(c, b, a);
}
}
}
```

Now comes the last part, the left and right rotation. Main idea is the same as AVL tree, but remember to handling the extra attrubites properly.

```
/**
* a
* b
* c x
*
* =>
*
* b
* c a
* x
*/
private _rightRotate(a: RedBlackNode) {
if (a.left === null) return;
// handle x
const b = a.left;
const x = b.right;
a.left = x;
if (x !== null) {
x.isLeft = true;
x.parent = a;
}
// handle b
const parent = a.parent;
b.parent = parent;
if (parent === null) {
this.root = b;
} else {
if (a.isLeft) {
parent.left = b;
b.isLeft = true;
} else {
parent.right = b;
b.isLeft = false;
}
}
// handle a
a.isLeft = false;
a.parent = b;
b.right = a;
}
/**
* a
* b
* x c
*
* =>
*
* b
* a c
* x
*
*/
private _leftRotate(a: RedBlackNode) {
if (a.right === null) return;
// handle x
const b = a.right;
const x = b.left;
a.right = x;
if (x !== null) {
x.isLeft = false;
x.parent = a;
}
// handle b
const parent = a.parent;
b.parent = parent;
if (parent === null) {
this.root = b;
} else {
if (a.isLeft) {
parent.left = b;
b.isLeft = true;
} else {
parent.right = b;
b.isLeft = false;
}
}
// handle a
a.isLeft = true;
a.parent = b;
b.left = a;
}
```

OK, that is the whole process. Let see all the code.

```
class RedBlackNode {
data: number;
left: RedBlackNode | null;
right: RedBlackNode | null;
parent: RedBlackNode | null;
isRed: boolean;
isLeft: boolean;
constructor(data: number) {
this.data = data;
this.left = null;
this.right = null;
this.parent = null;
this.isRed = true; // new node are red
this.isLeft = true; // this will be updated when inserting
}
};
class RedBlackTree {
private root: RedBlackNode | null = null;
insert(data: number) {
const node = new RedBlackNode(data);
if (this.root === null) {
this.root = node;
} else {
this._insert(this.root, node);
}
this._rebalance(node);
}
private _insert(parent: RedBlackNode, node: RedBlackNode) {
if (node.data < parent.data) {
if (parent.left === null) {
node.isLeft = true;
node.parent = parent;
parent.left = node;
} else {
this._insert(parent.left, node);
}
} else {
if (parent.right === null) {
node.isLeft = false;
node.parent = parent;
parent.right = node;
} else {
this._insert(parent.right, node);
}
}
}
private _rebalance(node: RedBlackNode) {
if (node.parent === null) {
node.isRed = false;
return;
}
if (node.isRed && node.parent.isRed && node.parent.parent !== null) {
/**
* a
* b c
* d
*
* d is node, b is aunt
*/
let aunt: RedBlackNode | null = null;
if (node.parent.isLeft) {
aunt = node.parent.parent.right;
} else {
aunt = node.parent.parent.left;
}
if (aunt === null || !aunt.isRed) {
this._rotate(node);
} else {
// color flip
// parent => black
// grandparent => red
// aunt => black
if (aunt !== null) {
aunt.isRed = false;
}
node.parent.parent.isRed = true;
node.parent.isRed = false;
}
}
this._rebalance(node.parent);
}
private _rotate(c: RedBlackNode): void {
const b = c.parent;
if (b === null) return;
const a = b.parent;
if (a === null) return;
if (c.isLeft) {
if (b.isLeft) {
/**
* a
* b
* c
*
* c is the node
*
* after rotation, tree becomes
*
* b
* c a
*
* make c and a red, b black
*/
this._rightRotate(a);
this._flipColor(b, c, a);
} else {
/**
* a
* b
* c
*
* c is the node
*
* right rotate by b
*
* a
* c
* b
*
* left rotate by a
*
* c
* a b
*
* make a and b red, c black
*
*/
this._rightRotate(b);
this._leftRotate(a);
this._flipColor(c, a, b);
}
} else {
if (!b.isLeft) {
/**
* a
* b
* c
*
* c is the node
*
* after rotation, tree becomes
*
* b
* a c
*
* make a and c red, b black
*/
this._leftRotate(a);
this._flipColor(b, a, c);
} else {
/**
* a
* b
* c
*
* c is the node
*
* left rotate by b
*
* a
* c
* b
*
* right rotate by a
*
* c
* b a
*
* make b and a red, c black
*/
this._leftRotate(b);
this._rightRotate(a);
this._flipColor(c, b, a);
}
}
}
private _flipColor(root: RedBlackNode, left: RedBlackNode, right: RedBlackNode): void {
root.isRed = false;
left.isRed = true;
right.isRed = true;
}
/**
* a
* b
* c x
*
* =>
*
* b
* c a
* x
*/
private _rightRotate(a: RedBlackNode) {
if (a.left === null) return;
// handle x
const b = a.left;
const x = b.right;
a.left = x;
if (x !== null) {
x.isLeft = true;
x.parent = a;
}
// handle b
const parent = a.parent;
b.parent = parent;
if (parent === null) {
this.root = b;
} else {
if (a.isLeft) {
parent.left = b;
b.isLeft = true;
} else {
parent.right = b;
b.isLeft = false;
}
}
// handle a
a.isLeft = false;
a.parent = b;
b.right = a;
}
/**
* a
* b
* x c
*
* =>
*
* b
* a c
* x
*
*/
private _leftRotate(a: RedBlackNode) {
if (a.right === null) return;
// handle x
const b = a.right;
const x = b.left;
a.right = x;
if (x !== null) {
x.isLeft = false;
x.parent = a;
}
// handle b
const parent = a.parent;
b.parent = parent;
if (parent === null) {
this.root = b;
} else {
if (a.isLeft) {
parent.left = b;
b.isLeft = true;
} else {
parent.right = b;
b.isLeft = false;
}
}
// handle a
a.isLeft = true;
a.parent = b;
b.left = a;
}
print() {
const q: (RedBlackNode | null)[] = [];
q.push(this.root);
while (true) {
const len = q.length;
for (let i = 0; i < len; i++) {
const v = q[i];
if (v !== null) {
q.push(v.left, v.right);
} else {
q.push(null, null);
}
}
const level = q.splice(0, len);
console.log(level.map(v => v === null ? "x" : `${v.isRed ? 'r' : 'b'}(${v.data})`).join(" "));
if (q.every(v => v === null)) break;
}
}
}
```

Then make some tests.

```
const t = new RedBlackTree();
t.insert(1);
t.insert(2);
t.insert(3);
t.insert(4);
t.insert(5);
t.insert(6);
t.insert(7);
t.insert(8);
t.insert(9);
t.print();
/**
b(4)
r(2) r(6)
b(1) b(3) b(5) b(8)
x x x x x x r(7) r(9)
*/
```

]]>Below code shows how to use stdin, stdout and stderr in nodejs.

```
process.stdin.on("data", (data) => {
const name = data.toString().trim();
if (name !== "") {
process.stdout.write("name: " + name + "\n");
} else {
process.stderr.write("invalid name");
process.exit();
}
});
```

Let's see the process.

```
$ node index.js
Tom
name: Tom
Jack
name: Jack
```

The most simple way to read/write file is to use the `readFileSync`

and `writeFileSync`

api.

```
const fs = require("fs");
let contents1 = fs.readFileSync("hello.txt", { encoding: "utf-8" });
console.log(contents1.toString());
fs.writeFileSync("hello.txt", "write to hello file", { encoding: "utf8" });
let contents2 = fs.readFileSync("hello.txt", { encoding: "utf-8" });
console.log(contents2.toString());
```

Callback is the traditional way for nodejs to handle async operations.

```
const fs = require("fs");
fs.readFile("hello.txt", { encoding: "utf-8" }, (err, contents) => {
if (err) {
console.error(err);
} else {
console.log(contents.toString());
fs.writeFile( "hello.txt", "write to hello file", { encoding: "utf-8" }, (err) => {
if (err) {
console.error(err);
} else {
fs.readFile( "hello.txt", { encoding: "utf-8" }, (err, contents) => {
if (err) {
console.error(err);
} else {
console.log(contents.toString());
}
}
);
}
}
);
}
});
```

As you can see, it is pretty long for integrate several callbacks together.

Promise is the most recommended way to handle async operations.

```
const fs = require("fs").promises;
Promise.resolve()
.then(() => {
return fs.readFile("hello.txt", { encoding: "utf8" });
})
.then((contents) => {
console.log(contents.toString());
})
.then(() => {
fs.writeFile("hello.txt", "write to hello file", { encoding: "utf-8" });
})
.then(() => {
return fs.readFile("hello.txt", { encoding: "utf-8" });
})
.then((contents) => {
console.log(contents.toString());
})
.catch((err) => {
console.error(err);
});
```

As you can see, we have 3 type api for handling file IO in nodejs: the sync api, the callback-based async api and the promised-based async api. In nodejs, a lot of apis have these 3 types. For async operations, it is always recommended to use promise-based api.

```
const fs = require("fs").promises;
fs.stat("hello.txt")
.then((stats) => {
console.log(stats);
})
.catch((err) => {
console.error(err);
});
```

```
Stats {
dev: 16777221,
mode: 33188,
nlink: 1,
uid: 502,
gid: 20,
rdev: 0,
blksize: 4096,
ino: 8637948036,
size: 19,
blocks: 8,
atimeMs: 1658405488047.815,
mtimeMs: 1658405486844.7258,
ctimeMs: 1658405486844.7258,
birthtimeMs: 1658404778790.4702,
atime: 2022-07-21T12:11:28.048Z,
mtime: 2022-07-21T12:11:26.845Z,
ctime: 2022-07-21T12:11:26.845Z,
birthtime: 2022-07-21T11:59:38.790Z
}
```

In below code, we use `fs.chmod`

to change file permissions and `fs.access`

to test it.

```
const fs = require("fs").promises;
const { constants } = require("fs");
Promise.resolve()
.then(() => {
return fs.chmod("hello.txt", 0o000);
})
.then(() => {
console.log("chmod success");
})
.catch(() => {
console.error("chmod fail");
})
.then(() => {
return fs.access("./hello.txt", constants.R_OK | constants.W_OK);
})
.then(() => {
console.log("can access");
})
.catch(() => {
console.error("cannot access");
})
.then(() => {
return fs.chmod("hello.txt", 0o777);
})
.then(() => {
console.log("chmod success");
})
.catch(() => {
console.error("chmod fail");
})
.then(() => {
return fs.access("./hello.txt", constants.R_OK | constants.W_OK);
})
.then(() => {
console.log("can access");
})
.catch(() => {
console.error("cannot access");
});
```

```
$ node index.js
chmod success
cannot access
chmod success
can access
```

In nodejs, we can use `fs.watch`

to watch file changes.

```
const fs = require("fs").promises;
(async () => {
try {
const watcher = fs.watch("hello.txt");
for await (const event of watcher) console.log(event);
} catch (err) {
console.error(err);
}
})();
```

```
$ node index.js
{ eventType: 'change', filename: 'hello.txt' }
{ eventType: 'change', filename: 'hello.txt' }
{ eventType: 'change', filename: 'hello.txt' }
{ eventType: 'change', filename: 'hello.txt' }
{ eventType: 'rename', filename: 'hello.txt' }
```

]]>The main purpose of AVL tree is to solve the balancing problem of binary search tree(BST). If you don't know what binary search tree is, please check my previous article first.

We know that, with binary search tree, we can search a value with average time complexity of `O(log(n))`

.

```
2
1 5
4 6
```

But what is the balancing problem? Take a look a below.

```
1
2
3
4
5
6
```

As you can see, the values are the same, but with different shape and still a valid BST. So if the tree is like this, then search time complexity becomes `O(n)`

.

This is the balancing problem. To solve this problem, whenever inserting a new value into a BST, AVL tree use rotation operations to adjust the tree to make it balanced.

Before we get to how rotation works, we need to know how to measure balance first.

AVL tree uses the height to measure balance. A node's height is the distance between current node to the furthest null node from it. In AVL tree, we save the node's height in the node structure.

```
type AVLNode = {
data: number;
height: number;
left: AVLNode | null;
right: AVLNode | null;
};
```

So if we want to get the height of the node, we can just access this attribute.

```
private getHeight(node: AVLNode | null): number {
return node === null ? 0 : node.height;
}
```

And to calculate this height value, we can get it from its children's height when traversal the tree.

```
private updateHeight(node: AVLNode) {
node.height = Math.max(this.getHeight(node.left), this.getHeight(node.right)) + 1;
}
```

Now we know the node's height, next is to define balance. We call a node is balances if the difference between its children's height is either 0, 1 or -1.

```
private getBalance(node: AVLNode | null): number {
return node === null ? 0 : this.getHeight(node.left) - this.getHeight(node.right);
}
```

OK, now we know how to measure balance, next is to how to handle it when we see an imbalanced node.

AVL tree uses rotation operations to handle imbalance. Specifically, there are 4 cases.

First, right-right rotation.

Take a look a below tree.

```
3
2 null
1 x
```

We can see that the node with value 3 is imbalanced. What we will do now is called right-right rotation. As the name says, we move 1/2/3 to the right. And because 3 is already the root node, so we move 3 as the right child. The result after moving is like below.

```
2
1 3
x null
```

The next thing should be noted is that node x should be moved as the node 3's left child.

This rotation can be expressed in code like below.

```
private rotateRight(node: AVLNode): AVLNode {
if (node.left === null) return node;
const left = node.left;
const leftRight = left.right;
left.right = node;
node.left = leftRight;
return left;
}
```

Second, left-left rotation.

Just the the contrary of right-right rotation, we rotate node to the left, and move the root node as the left child.

```
1
null 2
x 3
```

The result after moving is like below.

```
2
1 3
null x
```

Still, one thing needs to be noted that the node x should be moved as node 1's right child.

This rotation can be expressed in code like below.

```
private rotateLeft(node: AVLNode): AVLNode {
if (node.right === null) return node;
const right = node.right;
const rightLeft = right.left;
right.left = node;
node.right = rightLeft;
return right;
}
```

Third, right-left rotation.

Take a look at the tree below.

```
1
null 3
2 null
```

We can see that, node 2 is imbalanced, but the tree's shape is different from the right-right case.

what we will do for this case is do a right rotation for node 3 first.

```
1
null 2
null 3
```

Now it becomes left-left case, do the left-left rotation for node 1.

```
2
1 3
```

This rotation can be expressed in code like below.

```
node.right = this.rotateRight(node.right as AVLNode);
this.rotateLeft(node);
```

Forth, left-right rotation.

Take a look at the tree below.

```
3
1
null 2
```

Just like the contrary of the thrid case, we rotate node 1 to the left first.

```
3
2
1
```

Now it becomes right-right case.

```
2
1 3
```

This rotation can be expressed in code like below.

```
node.left = this.rotateLeft(node.left as AVLNode);
this.rotateRight(node);
```

OK, now we only have one thing left, which is how to decide which case we should apply.

The answer is still to use balance. This logic can be seen more clearly in code.

```
const balance = this.getBalance(node);
if (balance > 1) {
if (this.getBalance(node.left) < 0) {
node.left = this.rotateLeft(node.left as AVLNode);
}
return this.rotateRight(node);
}
if (balance < -1) {
if (this.getBalance(node.right) > 0) {
node.right = this.rotateRight(node.right as AVLNode);
}
return this.rotateLeft(node);
}
```

OK, that's all. Now let's see all the code.

```
type AVLNode = {
data: number;
height: number;
left: AVLNode | null;
right: AVLNode | null;
};
class AVLTree {
private root: AVLNode | null = null;
public insert(data: number) {
this.root = this._insert(data, this.root);
}
private _insert(data: number, node: AVLNode | null): AVLNode {
if (node == null) {
return { data, height: 1, left: null, right: null };
}
if (data < node.data) {
node.left = this._insert(data, node.left);
} else if (data > node.data) {
node.right = this._insert(data, node.right);
} else {
return node;
}
// recursively update every node's height from bottom to top
this.updateHeight(node);
return this.applyRotation(node);
}
private updateHeight(node: AVLNode) {
node.height = Math.max(this.getHeight(node.left), this.getHeight(node.right)) + 1;
}
private getHeight(node: AVLNode | null): number {
return node === null ? 0 : node.height;
}
private getBalance(node: AVLNode | null): number {
return node === null ? 0 : this.getHeight(node.left) - this.getHeight(node.right);
}
private rotateRight(node: AVLNode): AVLNode {
if (node.left === null) return node;
const left = node.left;
const leftRight = left.right;
left.right = node;
node.left = leftRight;
this.updateHeight(node);
this.updateHeight(left);
return left;
}
private rotateLeft(node: AVLNode): AVLNode {
if (node.right === null) return node;
const right = node.right;
const rightLeft = right.left;
right.left = node;
node.right = rightLeft;
this.updateHeight(node);
this.updateHeight(right);
return right;
}
private applyRotation(node: AVLNode): AVLNode {
const balance = this.getBalance(node);
if (balance > 1) {
if (this.getBalance(node.left) < 0) {
node.left = this.rotateLeft(node.left as AVLNode);
}
return this.rotateRight(node);
}
if (balance < -1) {
if (this.getBalance(node.right) > 0) {
node.right = this.rotateRight(node.right as AVLNode);
}
return this.rotateLeft(node);
}
return node;
}
print() {
const q: (AVLNode | null)[] = [];
q.push(this.root)
while (true) {
const len = q.length;
for (let i = 0; i < len; i++) {
const v = q[i];
if (v !== null) {
q.push(v.left, v.right);
} else {
q.push(null, null);
}
}
const level = q.splice(0, len);
console.log(level.map(v => v === null ? "x" : v.data).join(" "));
if (q.every(v => v === null)) break;
}
}
}
```

And let's insert values to see the result.

```
const t = new AVLTree();
t.insert(1);
t.insert(2);
t.insert(3);
t.insert(4);
t.insert(5);
t.insert(6);
t.insert(7);
t.insert(8);
t.insert(9);
t.print()
```

Results after format by hand is as below. You can see that the self-balancing is working.

```
4
2 6
1 3 5 8
x x x x x x 7 9
```

]]>Let's take the box blur task as an example. Box blur uses a kernel window to slide over the whole image, calculate the average and generate the blurred image. A 3*3(radius=1) kernel is like below.

```
1 1 1
1 1 1
1 1 1
```

The blur process can be seen as below.

```
kernel pixel multiply sum average
-----------------------------------------------
1 1 1 1 2 3 1*1 1*2 1*3 - - - - - -
1 1 1 * 4 5 6 => 1*4 1*5 1*6 => - sum - => - sum/9 -
1 1 1 7 8 9 1*7 1*8 1*9 - - - - - -
sum/9 = (1+2+3+4+5+6+7+8+9)/9
```

After we know what the task is, it is not hard to implement it in code. The leetcode Image Smoother problem is the same problem, let's try to solve it in code.

```
function imageSmoother(img: number[][]): number[][] {
const img2 = Array.from({ length: img.length }, (_, i: number) => {
return Array.from({ length: img[i].length }, (_, j: number) => {
return img[i][j];
});
});
const radius = 1;
for (let i = 0; i < img.length; i++) {
for (let j = 0; j < img[i].length; j++) {
let sum = 0;
let count = 0;
for (let ii = i - radius; ii <= i + radius; ii++) {
for (let jj = j - radius; jj <= j + radius; jj++) {
if (ii < 0) continue;
if (jj < 0) continue;
if (ii >= img.length) continue;
if (jj >= img[i].length) continue;
count += 1;
sum += img[ii][jj];
}
}
img2[i][j] = Math.floor(sum / count);
}
}
return img2;
};
```

As you can see, the process is very clear. We iterate all pixels, and calculate window average value for each pixels. Let image's size as `m * n`

, then window size as `w`

, then time complexity is `O(mnww)`

.

How can we speed up this process? That's what summed area table used for. Like prefix sum, a summed area table show the sumed values from left top coordinate to current coordinate. See the example below.

```
img
1 2 3
4 5 6
7 8 9
table
1 1+2 1+2+3
1+4 1+2+4+5 1+2+3+4+5+6
1+4+7 1+2+4+5+7+8 1+2+3+4+5+6+7+8+9
```

Now let's consider how to calcuate this table efficiently. We certainly shouldn't calculate from scratch for each position. Actually, if you look above example closely, you may find every value of the table has a relation with its left value, top value and left top value. If current position has coordinate `(i,j)`

, then we can calculate its value using below formula.

```
table[i][j] = img[i][j] + table[i-1][j] + table[i][j-1] - t[i-1][j-1];
```

So with this formula, we can calculate the table in `O(n)`

time complexity.

Next thing to consider is, how this table can be used to help solving the problem.

Suppose we have an image below. What we want to do now is to calculate the sum from position `x`

to position `y`

.

```
. . . . . . . . .
. a . . c . . . .
. . x . . . . . .
. . . . . . . . .
. b . . y . . . .
. . . . . . . . .
```

With the summed area table, we can calcuate this targeted area's sum using below formula.

```
const target = table[yi][yj] - table[bi][bj] - table[ci][cj] + table[ai][aj]
```

Its not very hard to understand, we just subtract the extra sum(left(`b`

) and top(`c`

)). And because we subtrack the left-top(`a`

) area twice, we add one back.

OK, let write all of this in code now.

```
function imageSmoother(img: number[][]): number[][] {
const m = img.length;
const n = img[0].length;
const img2 = Array.from({ length: m }, (_, i: number) => {
return Array.from({ length: n }, (_, j: number) => {
return img[i][j];
});
});
// summed area table
const t = Array.from({ length: m }, () => Array.from({ length: n }, () => 0));
t[0][0] = img[0][0];
for (let i = 1; i < m; i++) {
t[i][0] = t[i - 1][0] + img[i][0];
}
for (let j = 1; j < n; j++) {
t[0][j] = t[0][j - 1] + img[0][j];
}
for (let i = 1; i < m; i++) {
for (let j = 1; j < n; j++) {
t[i][j] = img[i][j] + t[i - 1][j] + t[i][j - 1] - t[i - 1][j - 1];
}
}
const radius = 1;
for (let i = 0; i < img.length; i++) {
for (let j = 0; j < img[i].length; j++) {
// calculate top index and its value
const topI = i - radius - 1;
const topJ = j + radius >= n ? n - 1 : j + radius;
const topValue = topI >= 0 ? t[topI][topJ] : 0;
// calculate left index and its value
const leftI = i + radius >= m ? m - 1 : i + radius;
const leftJ = j - radius - 1;
const leftValue = leftJ >= 0 ? t[leftI][leftJ] : 0;
// calculate top-left index and its value
const topLeftI = i - radius - 1;
const topLeftJ = j - radius - 1;
const topLeftValue = (topLeftI >= 0 && topLeftJ >= 0) ? t[topLeftI][topLeftJ] : 0;
// calculate bottom-right index and its value
const bottomRightI = i + radius >= m ? m - 1 : i + radius;
const bottomRightJ = j + radius >= n ? n - 1 : j + radius;
const bottomRightValue = t[bottomRightI][bottomRightJ]
const sum = bottomRightValue - topValue - leftValue + topLeftValue;
// calculate valid numbers of cells
const row = (i - 0 > radius ? radius : i - 0) + 1 + (m - i - 1 > radius ? radius : m - i - 1);
const column = (j - 0 > radius ? radius : j - 0) + 1 + (n - j - 1 > radius ? radius : n - j - 1);
const count = row * column;
img2[i][j] = Math.floor(sum / count);
}
}
return img2;
};
```

The above may seems a lot, but the whole process is very straightforward. The extra code is used to handle edge cases.

As you can see, with summed area table, we can calculate every pixel's window sum in `O(1)`

time complexity. So total time complexity reduced to `O(mn)`

.

Say we want to multiply 2 number: x and y.

The first step is to split each number into 2 half. For example, `12345`

can be split into `123`

and `45`

and expressed as `123 * 100 + 45`

. So, in this way, we can express the x and y in below. `n`

is the max length between x and y.

```
x = a * 10^(n/2) + b
y = c * 10^(n/2) + d
```

Now let's try to multiply these 2 parts.

```
x * y
= (a * 10^(n/2) + b) * (c * 10 ^(n/2) + d)
= (a * 10^(n/2)) * (c * 10 ^(n/2)) + ad*(10^(n/2)) + bc*(10^(n/2)) + bd
= ac * 10^(2*(n/2)) + (ad + bc)*10^(n/2) + bd
```

So to get the result of `x * y`

, we need to get `ac`

, `bd`

and `ad+bc`

first.

And `ad+bc`

can be expressed as:

```
ad + bc = (a + b)*(c + d) - ac - bd
```

So, in the end, what we only need to know is `ac`

and `bd`

.

Now, how can we get `ac`

and `bd`

? Well, since it is still multiplication, we can calculate these using the same process recursively, until we find x or y is 1 digit number, then we can stop the recursion and do the multiplication in the normal way.

As you can see, this whole process is what the divide and conquer means. Big x and y are divided into small a,b,c,d, which can be divided recursively further.

With all this in mind, let see them in code.

```
function multiply(x: string, y: string): string {
if (x.length === 0) return y;
if (y.length === 0) return x;
// 1 digit number, use normal multiply
if (x.length === 1) return singleMultiply(y, x);
if (y.length === 1) return singleMultiply(x, y);
// divide each into 2 parts
const half = Math.floor(Math.max(x.toString().length, y.toString().length) / 2);
const xMid = x.length - half;
const a = xMid <= 0 ? "0" : x.slice(0, xMid);
const b = x.slice(xMid < 0 ? 0 : xMid);
const yMid = y.length - half;
const c = yMid <= 0 ? "0" : y.slice(0, yMid);
const d = y.slice(yMid < 0 ? 0 : yMid);
// calculate key elements
const ac = multiply(a, c);
const bd = multiply(b, d);
const ad_plus_bc = subtract(subtract(multiply(add(a, b), add(c, d)), ac), bd);
// calculate final result
return add(add(pow10(ac, 2 * half), pow10(ad_plus_bc, half)), bd);
};
```

Since I want to avoid converting input number string into number directly, so I prepare the string version of `add`

, `subtract`

and `pow10`

functions, which use the standard operations we learn from elementary school to do each operations.

```
// x * 10^y
function pow10(x: string, y: number): string {
while (y-- > 0) {
x += "0";
}
return x;
}
// y: 1 digit
function singleMultiply(x: string, y: string): string {
const res: number[] = [];
let carry = 0;
const base = "0".charCodeAt(0);
const yv = y.charCodeAt(0) - base;
for (let i = x.length - 1; i >= 0; i--) {
const v = (x.charCodeAt(i) - base) * yv + carry;
res.push(v % 10);
carry = Math.trunc(v / 10);
}
if (carry > 0) {
res.push(carry);
}
res.reverse();
return trimStart0(res.join(""));
}
function add(x: string, y: string): string {
const res: number[] = [];
let carry = 0;
const base = "0".charCodeAt(0);
for (let i = x.length - 1, j = y.length - 1; i >= 0 || j >= 0; i--, j--) {
const v1 = i >= 0 ? x.charCodeAt(i) - base : 0;
const v2 = j >= 0 ? y.charCodeAt(j) - base : 0;
const v = v1 + v2 + carry;
res.push(v % 10);
carry = Math.trunc(v / 10);
}
if (carry > 0) {
res.push(carry);
}
res.reverse();
return res.join("");
}
// value of x >= value of y
function subtract(x: string, y: string): string {
const res: number[] = [];
let carry = 0;
const base = "0".charCodeAt(0);
for (let i = x.length - 1, j = y.length - 1; i >= 0 || j >= 0; i--, j--) {
const v1 = i >= 0 ? x.charCodeAt(i) - base : 0;
const v2 = j >= 0 ? y.charCodeAt(j) - base : 0;
const v = v1 - v2 - carry;
res.push(v < 0 ? v + 10 : v);
carry = v < 0 ? 1 : 0;
}
if (carry > 0) {
res.push(carry);
}
res.reverse();
return trimStart0(res.join(""));
}
function trimStart0(x: string): string {
return x.replace(/^0+(?=\d)/, "");
}
```

In the end, don't forget to use the leetcode problem Multiply Strings to test the code.

]]>To understand dual pivot quick, you need to have a basic understanding of quick sort. If you don't, check my previous article about quick sort. Then, let's get started.

We know that in quick sort, we should use a pivot to split the array into 2 parts. All the values in left part is lower than the pivot value, all the values in the right part is larger than the pivot value. So we can continue to use the same process to these 2 subarrays. Code is like below.

```
function quickSort(nums: number[], low: number, high: number) {
if (low > high) return;
const mid = partition(nums, low, high);
quickSort(nums, low, mid - 1);
quickSort(nums, mid + 1, high);
}
```

In dual pivot quick sort, we use 2 pivot (pivot 1 and pivot 2) to split the array into 3 parts. Other process is the same. Code is similar too.

```
function dualPivotQuickSort(nums: number[], low: number, high: number) {
if (low > high) return;
const [p1, p2] = partition(nums, low, high);
dualPivotQuickSort(nums, low, p1 - 1);
dualPivotQuickSort(nums, p1 + 1, p2 - 1);
dualPivotQuickSort(nums, p2 + 1, high);
}
```

In quick sort, to split array into 2 part, we select a pivot, use a for loop swap all values lower than pivot to the left, and all the values larger than the pivot will be in the right automatically. Code is like below.

```
function partition(nums: number[], low: number, high: number): number {
let pivot = nums[high];
let p = low;
for (let i = low; i < high; i++) {
if (nums[i] <= pivot) {
[nums[i], nums[p]] = [nums[p], nums[i]];
p += 1;
}
}
[nums[high], nums[p]] = [nums[p], nums[high]];
return p;
}
```

The problem is how to split it into 3 parts in `O(n)`

time complexity? Actually, this 3 part split problem is very similiar to the Dutch national flag problem, check my previous article about it.

The idea is, use 2 pointers, one from left, one from right. Move all the values lower than pivot 1 to the left, and move all the values larger than pivot 2 to the right. And the remaining values are between pivot 1 and pivot 2. Now let's see the code.

```
function swap(nums: number[], i: number, j: number) {
[nums[i], nums[j]] = [nums[j], nums[i]];
}
function partition(nums: number[], low: number, high: number): [number, number] {
if (nums[low] > nums[high]) {
swap(nums, low, high);
}
let leftIndex = low + 1;
let rightIndex = high - 1;
let i = low + 1;
while (i <= rightIndex) {
if (nums[i] < nums[low]) {
swap(nums, i++, leftIndex++);
} else if (nums[i] >= nums[high]) {
swap(nums, i, rightIndex--);
} else {
i += 1;
}
}
swap(nums, low, --leftIndex);
swap(nums, high, ++rightIndex);
return [leftIndex, rightIndex];
}
```

OK, that's all of it. Don't forget to use the leetcode problem Sort an Array to test the code.

```
function sortArray(nums: number[]): number[] {
dualPivotQuickSort(nums, 0, nums.length - 1);
return nums;
};
```

]]>Say we have 4 bytes `0xaa, 0xbb, 0xcc, 0xdd`

and we want to interpret these 4 bytes into a number, specifically a unsigned 32-bit interger. Basically, there are 2 ways computers interpret them: `0xaabbccdd`

or `0xddccbbaa`

. The first one is called big endianness, then the second one is called small endianness. You can see the difference more clearly in below.

```
0xaa, 0xbb, 0xcc, 0xdd
0xaabbccdd => big endianness
0xddccbbaa => small endianess
```

So we must know the byte endianness before we can read/write data properly.

In javascript, which endianness is used depends on the underlying CPU architecture.

So how can we know which one is used in runtime? We can check it like below.

```
const v = new Uint32Array(new Uint8Array([0xaa, 0xbb, 0xcc, 0xdd]).buffer)[0]
// is big endianness?
v === 0xaabbccdd
// false
// is small endianness?
v === 0xddccbbaa
// true
```

OK, now we know the endianness, then we can assemble data in the right byte order manually.

Or, we can use Data view api to assemble data, which we can pass endianness parameters and the api will do the hard working for us.

```
const arrayBuffer = new ArrayBuffer(4)
const view = new DataView(arrayBuffer);
new Uint8Array(arrayBuffer)
// Uint8Array(4) [0, 0, 0, 0, buffer: ArrayBuffer(4), byteLength: 4, byteOffset: 0, length: 4, Symbol(Symbol.toStringTag): 'Uint8Array']
// write value in little endinness
view.setUint32(0, 0xaabbccdd, true)
new Uint8Array(arrayBuffer)
// Uint8Array(4) [221, 204, 187, 170, buffer: ArrayBuffer(4), byteLength: 4, byteOffset: 0, length: 4, Symbol(Symbol.toStringTag): 'Uint8Array']
// write value in big endinness
view.setUint32(0, 0xaabbccdd, false)
new Uint8Array(arrayBuffer)
// Uint8Array(4) [170, 187, 204, 221, buffer: ArrayBuffer(4), byteLength: 4, byteOffset: 0, length: 4, Symbol(Symbol.toStringTag): 'Uint8Array']
// read value in little endianness
view.getUint32(0, true)
// 3721182122
// read value in big endianness
view.getUint32(0, false)
// 2864434397
```

]]>`O(n)`

.
The key idea of Z algorithm is to build an Z array, which stores the matching length starts from each character. For example, if we have a string `ababc`

, then we initialize an array with the same length `[0,0,0,0,0]`

. The first element means, how long could a string start from the first character to match the original string. So just string matching itself. So first element is the length of the string. `[5,0,0,0,0]`

. Then comes second element. Same logic, how long could `babc`

matching the original string? Of course, its 0, so `[5,0,0,0,0]`

. Same logic for other characters.

```
ababc
=> 50200
```

Before we dig into how to get this array, let consider how this array be helpful for string matching first. The idea is simple. Say if we want to find `needle`

in a `haystack`

. We can concat them and put a special character in between like `needle$haystack`

. Then we calculate Z array for this string. Then we can iterate Z array, if there is a value equals to the length of the `needle`

, then it means there is a match.

OK, now let's see how to calculate the Z array.

We could use the brute force way to calculate it. But that's not efficient at all, time complexity becomes `O(n^2)`

.

How to speed up this process? See an example below.

```
i
a b a b c d a b a b e f
0 2 0 0 0 4 0 2 0 0 0
- - - - - - - -
```

See the position of `i`

, it has a value 4, which means a substring start from this character with window 4 equals first 4 characters of the string. Since the string is the same, then its value in Z array should be equal too. So `z[i+1] = z[1]`

, `z[i+2] = z[2]`

, and `z[i+3] = z[3]`

. Wow, this really could speed up things.

But really? Take a look at another example.

```
i
a b a b a b c d a b a b e f
_ 0 4 0 2 0 0 0 4 0 2 0 0 0
- - - - - - - -
* *
```

In this example, at the end of the first window, there are 2 more characters matching, makes them not equal.

Let's see one more example.

```
i
a b a b c d a b a b a b
_ 0 2 0 0 0 4 0 4 0 2 0
- - - - - - - -
* *
```

This time, at the end of the second window, there are 2 more characters matching. also makes them not equal.

So, as you can see now, we can use this feature, but with limits. We need to check if current matching part could exceed the window. If it could, then we should start from the window, and match every characters manually again.

Now, let's see the code.

```
function strStr(haystack: string, needle: string): number {
const s = needle + "$" + haystack;
const z = [s.length];
let i = 1;
let window = 0;
while(i < s.length) {
// calculate the window manually
while(i + window < s.length && s[window] === s[i+window]) window++;
z[i] = window;
// if window is 0, then its no use, move to next
if (window === 0) {
i++;
continue;
}
// we have a window, then calculate values inside the window
let j = 1;
// j + z[j] means, if matching part could exceed the window
while(j < window && j + z[j] < window) {
z[i+j] = z[j];
j++;
}
// if could exceed, move to that position, start match manully again
i += j;
window -= j;
}
for (let i = 0; i < s.length; i++) {
if (z[i] === needle.length) {
return i - needle.length - 1;
}
}
return -1;
};
```

]]>`$`

character, but we only want the number, without the `$`

in outcome. This is what look ahead and look behind used for.
There are totally 4 types:

- Positive lookahead: check if targeted pattern followed by specified pattern
- Negative lookahead: check if targeted pattern not followed by specified pattern
- Positive lookbehind: check if targeted pattern preceded by specified pattern
- Negative lookbehind: check if targeted pattern not preceded by specified pattern

Now let's see some examples to see how they works.

Below example shows only match numbers followed by `%`

.

```
let str = "1# 2% 3 4%";
str.match(/\d+/g)
// ['1', '2', '3', '4']
str.match(/\d+(?=%)/g)
// ['2', '4']
```

Use the same example string, to match numbers not followed by `%`

.

```
str.match(/\d+(?!%)/g)
// ['1', '3']
```

Below example shows only match numbers preceded by `%`

.

```
let str = "#1 %2 3 %4";
str.match(/\d+/g)
// ['1', '2', '3', '4']
str.match(/(?<=%)\d+/g)
// ['2', '4']
```

Use the same example string, to match numbers not preceded by `%`

.

```
str.match(/(?<!%)\d+/g)
// ['1', '3']
```

]]>We know that a image contains pixels. Each pixels contains rgb(or rgba) values. Each value is a unsigned int, with value from 0-255. If the image is a grayscale image, then its rgb values are the same, so this gray image can be seen as a 2d array of values. If the gray image's size is 3 * 2, then can be expressed in below.

```
17 28 125
44 9 211
```

Let's express this image in 8-bits.

```
00010001 00011100 01111101
00101100 00001001 11010011
```

Each value can be expressed in 8 bits. From left to right, the leftest bit is called most significant bit(MSB), then rightest bit is called the least significant bit(LSB). Take the first value (17) as an example.

```
0 0 0 1 0 0 0 1
MSB bit-7 bit-6 bit-5 bit-4 bit-3 bit-2 LSB
```

So why called MSB and LSB? Because, if we change the value of the most significant bit, then the whole value will be changed significantly. If we change the value of the least significant bit, then the whole value will be changed just a little(by 1). We will see this change later.

A bit plane a image with values which just take specific bit position of the original value. For example, if we take the least significant bit of each value, and use them as a new image, then this is a bit plane. Same logic, we can take bit-2 of each value and use them a new image too, then this is another bit plane. So because each value has 8 bit, we can create 8 bit plane. This process is called bit plane slicing.

Let's see the code how to do the bit plane slicing.

```
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<img src="./download.jpg" alt="" onload="start()" style="display: none;">
<script>
function createCanvas(width, height) {
const c = document.createElement("canvas");
c.width = width;
c.height = height;
document.body.appendChild(c);
const ctx = c.getContext("2d");
return ctx;
}
function createPlane(width, height, originalData, planeNum) {
const ctx = createCanvas(width, height);
const imgData = ctx.getImageData(0, 0, width, height);
for (let i = 0; i < imgData.data.length; i++) {
if ((i + 1) % 4 === 0) {
imgData.data[i] = originalData.data[i];
} else {
imgData.data[i] = (originalData.data[i] & (1 << planeNum)) * 255;
}
}
ctx.putImageData(imgData, 0, 0);
}
function start() {
const img = document.querySelector("img");
const width = img.width;
const height = img.height;
const originalCtx = createCanvas(width, height);
originalCtx.drawImage(img, 0, 0);
const originalData = originalCtx.getImageData(0, 0, width, height);
// gray
for (let i = 0; i < originalData.data.length; i += 4) {
const v = (originalData.data[i] + originalData.data[i + 1] + originalData.data[i + 2]) / 3;
originalData.data[i] = v;
originalData.data[i + 1] = v;
originalData.data[i + 2] = v;
}
originalCtx.putImageData(originalData, 0, 0);
createPlane(width, height, originalData, 0);
createPlane(width, height, originalData, 1);
createPlane(width, height, originalData, 2);
createPlane(width, height, originalData, 3);
createPlane(width, height, originalData, 4);
createPlane(width, height, originalData, 5);
createPlane(width, height, originalData, 6);
createPlane(width, height, originalData, 7);
}
</script>
</body>
</html>
```

If you run the code above, you should see an image like below. The first image is the original gray image. And later is the bit plane image from LSB to MSB.

As you can see from the image, the MSB bit plane contains the most information, and the LSB bit plane contains the least information.

Last thing, the bit plane compression is just store the information of the MSB of each pixels. When in compression, each MSB stored one by one in bits, and when in decompression, MSB will be restored back to pixels values.

]]>The image below shows what the problem requires. We need to traverse the 2-dimensional array diagonally to get a 1-dimemsional array.

We could follow what the problem says, simulate the process to get the output. But I found that's too boring. Then I found a solution which is very clever. Let's me use this algorithm to solve this problem.

Let's consider this 2-dimensional array.

```
1 2 3
3 4 5
7 8 9
```

Express this array using element's indices.

```
[
(0,0), (0,1), (0,2),
(1,0), (1,1), (1,2),
(2,0), (2,1), (2,2),
]
```

Group them diagonally, as the problem says.

```
[
[(0,0)],
[(0,1),(1,0)],
[(0,2),(1,1),(2,0)],
[(1,2),(2,1)],
[(2,2)]
]
```

What pattern do you see? Yes, if the sum of the indices are the same, then they belong to the same group.

So now we can get groups one by one. One last thing to do, we need to adjust the direction. This is simple too. If the array's index is even, then reverse them.

That's all the process, let's see the code.

```
function findDiagonalOrder(mat: number[][]): number[] {
// grouping array
let groups: number[][][] = Array.from({ length: mat.length + mat[0].length - 1 }, _ => []);
for (let i = 0; i < mat.length; i++) {
for (let j = 0; j < mat[i].length; j++) {
groups[i + j].push([i, j]);
}
}
let result: number[] = [];
for (let i = 0; i < groups.length; i++) {
if (i % 2 === 0) {
groups[i].reverse();
}
for (let j = 0; j < groups[i].length; j++) {
result.push(mat[groups[i][j][0]][groups[i][j][1]]);
}
}
return result;
};
```

]]>Its idea is very simple. Let's see an example.

Say we have a string `aaaabbbccd`

, with RLE, we use a form of `[frequency][character]`

to express this string. So we have 4's a, 3's b, 2'c, and 1'd, then we can express it as `4a3b2c1d`

. And That's it. You can see that, if the original data have a lot of repetive pattern, then it is very suitable to use RLE for compression.

Leetcode problem Decompress Run-Length Encoded List can be use to practise how to decode a RLE data.

```
function decompressRLElist(nums: number[]): number[] {
let result: number[] = [];
for (let i = 0; i < nums.length - 1; i += 2) {
for (let j = 0; j < nums[i]; j++) {
result.push(nums[i + 1]);
}
}
return result;
};
```

As you can see, its very simple, just follow the algorithm, put repetive characters into result array.

Leetcode problem String Compression can be used to practise the encoding of RLE. Note that this problem requires that if the frequency is 1, then just fill in the character.

```
function compress(chars: string[]): number {
let i = 0;
let j = 0;
while (i < chars.length) {
let k = i;
while (++k, k < chars.length, chars[k] === chars[i]);
let length = (k - i).toString();
chars[j++] = chars[i]; // fill in the character
if (length !== "1") {
[...length].forEach(char => {
chars[j++] = char; // fill in the frequency
})
}
i = k;
}
return j;
}
```

]]>In computer, all things are bits. Bits can be seen as numbers. So how to express characters with numbers? Answer is using a table to map a number to a character.

The so-called ascii table is a typical one. In ascii, each byte is used to express one character. So in total, ascii can express 256(2^8) number of characters. This is enough for English, but for other language like Japanese, this simple table is definitely not enough.

So to express all the languages in the world, a table called unicode was invented. In unicode, we still use numbers to express characters. In unicode, these numbers are called code point. There are so many characters in the world, so we need big numbers to express them. So instead of 1 byte, in unicode, 4 bytes are used to store one number.

If we use 4 bytes to express all characters, then this is the UTF-32 encoding. This is easy but at the same we may waste a lot of bytes. For example, for small code points, the first 3 bytes may always be 0, only the last byte is used. So to avoid this problem, normally we use UTF-8.

Compared to UTF-32, UTF-8 is a variable length encoding algorithm. Which means for different character, different length of bytes may be used. Compared with fixed length encoding algorithm, variable length encoding algorithm needs to device a mechanism to divide each characters. For example, for UTF-32, we know every 4 bytes stands for a character, so we can just for loop the whole bytes and divide them by 4. But for UTF-8, a character could take 1/2/3/4 bytes. We need to know how to decide which bytes belong to which characters.

With all the above background, let see the details of UTF-8 and see how it solve the above problems.

Take a look at the image blew(taken from wiki).

We can see that, in UTF-8, we can check the first several bits to see how many bytes current character takes. For example, if first bit is `11110`

, then this is the first byte of a 4-byte character. Then bytes start with bits `10`

means it is a continue byte, which means that it is not the start byte of a character. Sample code could be like below.

```
if (byte >> 3 === 0b11110) {
i += 4;
} else if (byte >>> 4 === 0b1110) {
i += 3;
} else if (byte >>> 5 === 0b110) {
i += 2;
} else if (byte >> 7 === 0) {
i += 1;
} else {
throw new Error('invalid byte');
}
```

With this technique, we can group bytes for the same characters. Next, we need to calculate code point value from bytes. The process is take all other bits, as the all bits of the code point. Set bits from left to right one by one like below.

```
11110xxx
10xxxxxx
10xxxxxx
10xxxxxx
```

This process can be achieved by bits operations, like below.

```
codePoint = ((byte & 0b111) << 18) | (readContinueByte(buf[i + 1]) << 12) | (readContinueByte(buf[i + 2]) << 6) | readContinueByte(buf[i + 3]);
```

OK, I think that is all we need to know. Let's write a decode function to decode UTF-8 encoded binary values into characters.

```
function decode(buf: Uint8Array): string {
let i = 0;
let codePoint: number;
let decoded: string[] = [];
function readContinueByte(byte: number): number {
if (byte >> 6 !== 0b10) throw new Error(`invalid byte, expect continue byte: ${byte.toString(2)}`);
return byte & 0b111111;
}
while (i < buf.length) {
const byte = buf[i];
if (byte >> 3 === 0b11110) {
codePoint = ((byte & 0b111) << 18) | (readContinueByte(buf[i + 1]) << 12) | (readContinueByte(buf[i + 2]) << 6) | readContinueByte(buf[i + 3]);
i += 4;
} else if (byte >>> 4 === 0b1110) {
codePoint = ((byte & 0b1111) << 12) | (readContinueByte(buf[i + 1]) << 6) | readContinueByte(buf[i + 2]);
i += 3;
} else if (byte >>> 5 === 0b110) {
codePoint = ((byte & 0b11111) << 6) | readContinueByte(buf[i + 1]);
i += 2;
} else if (byte >> 7 === 0) {
codePoint = byte;
i += 1;
} else {
throw new Error('invalid byte');
}
decoded.push(String.fromCodePoint(codePoint));
}
return decoded.join("");
}
const text = 'Hello, ðŸ˜„';
const buf = new TextEncoder().encode(text);
const decoded = decode(buf);
console.log({text, buf, decoded});
/**
{
text: "Hello, ðŸ˜„",
buf: Uint8Array(29) [
72, 101, 108, 108, 111, 44, 32,
227, 129, 147, 227, 130, 147, 227,
129, 171, 227, 129, 161, 227, 129,
175, 227, 128, 129, 240, 159, 152,
132
],
decoded: "Hello, ðŸ˜„"
}
*/
```

]]>`O(n)`

.
Before we get to details of this algorithm, let's refresh our memory to see how the brute force way works.

Say we have two string `haystack`

and `needle`

, we want to find `needle`

in `haystack`

.

```
haystack: aaaxaaaa
needle: aaaa
```

The brute force way is to iterate the haystack and compare each character in each iteration.

```
aaaxaaaa
aaaa
aaaa
aaaa
aaaa
aaaa
```

So the time complexity is `O(mn)`

, for m is the length of needle, and n is the length of haystack.

KnuthMorrisPratt algorithm is an approach based on this brute force way. Now let's see what the improvement is.

In above example, when we find one unmatch character, we move one character to the right, and start matching from the beginning again.

```
0 1 2 3 4 5 6 7
a a a x a a a a
1. a a a a
2. a a a a
```

But when we move to character `x`

and finds an unmatch, we already have some valuable information. That information is, we know that first 3 character `aaa`

match with the first 3 character of needle. We could somehow make use of this information to speed up the process.

Let's use `i`

to express current start indice of haystack and `j`

to express current start indice of needle. We know now that if `i`

is 0, then we will bump into an unmatch, so we need to move `i`

to the right by 1, and compare `aaxa`

with needle again.

```
i
0 1 2 3 4 5 6 7
a a a x a a a a
j
0 1 2 3
a a a a
```

Forget about `x`

for the time being, just consider the first 3 characters first. The first time, we already compare first 3 characters and there is a match. And the second time, we need to compare the `haystack.slice(1,3)`

with `needle.slice(0,2)`

. Do you see the pattern here? `haystack.slice(1,3)`

can be seen as `needle.slice(1,3)`

because of the previous match. So basically, we are compare the needle's prefix `(0,2)`

with its suffix `(1,3)`

now.

```
0 1 2
a a a x a a a a a
1. a a a a
2. a a a
```

If a string's prefix is equal to its suffix, then we call this happy prefix. You can checkout to my previous article Longest Happy Prefix to see how to calculate happy prefix.

So if we can somehow know this is the needle's happy prefix, then we don't need to compare this 2 characters again. We can just move `j`

to needle's longest happy prefix and then compare `j`

with `i`

directly.

```
i
0 1 2 3 4 5 6 7
a a a x a a a a
j
0 1 2 3
a a a a
i don't need to be moved to index 1
j can be moved to longest happy prefix, index 2
```

If the longest happy prefix doesn't match again, follow the same process, move `j`

to second longest happy prefix index, until `j`

is 0.

```
i
0 1 2 3 4 5 6 7
a a a x a a a a
j
0 1 2 3
a a a a
```

If `j`

is 0, and there is still no match, then move `i`

directly to the next indice, we don't need to move `i`

to 1 ever.

```
i
0 1 2 3 4 5 6 7
a a a x a a a a
j
0 1 2 3
a a a a
```

In this way, the indice `i`

will never come back, we just move `j`

back and forth.

This is all the details. Now let's see the code.

```
function strStr(haystack: string, needle: string): number {
if (needle === "") return 0;
// calculate happy prefix for needle
function getlps(s: string) {
let i = 1;
let j = 0;
let lps = Array.from({ length: s.length }, _ => 0);
while (i < s.length) {
if (s.charAt(i) === s.charAt(j)) {
lps[i++] = ++j;
} else {
if (j === 0) {
lps[i++] = 0;
} else {
j = lps[j - 1];
}
}
}
return lps;
}
const lps = getlps(needle);
let i = 0;
let j = 0;
while(i < haystack.length) {
if (haystack.charAt(i) === needle.charAt(j)) {
// if current character match, move forward
i += 1;
j += 1;
} else {
if (j === 0) {
// if j is 0, move i forward directly
i += 1;
} else {
// or move j back to the longest happy prefix index for already matched part
j = lps[j-1]
}
}
if (j === needle.length) {
return i - needle.length;
}
}
return -1;
};
```

Don't forget to use leetcode Implement strStr() problem to test if the code is right.

]]>This problem is very easy to understand. A happy prefix is a prefix and also is a suffix of a string. For example, if we have a string `level`

, first calculate the prefix: `l`

, `le`

, `lev`

, `leve`

, then calculate the suffix `l`

, `el`

, `vel`

, `evel`

. And we need to find the longest common one, which is `l`

.

We can use two pointers and a temporary array to solve this problem. Let's use an example to show the process.

Say we have a string `aabaabaaa`

, initialize an array with the same length `[]`

and two pointer `i = 1, j = 0`

.

Step 1: initial

```
j i
a a b a a b a a a
[0 ]
```

Step 2: compare `s[i]`

and `s[j]`

, its equal, move j, fill array with j , and move i

```
j i
a a b a a b a a a
[0 1 ]
```

Step 3: compare again, its not equal, move j to `j = array[j-1]`

```
j i
a a b a a b a a a
[0 1 ]
```

Step 4: compare again, not equal and j is 0, then fill array with 0, and move i

```
j i
a a b a a b a a a
[0 1 0 ]
```

Step 5: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 ]
```

Step 6: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 2 ]
```

Step 7: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 2 3 ]
```

Step 8: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 2 3 4 ]
```

Step 9: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 2 3 4 5 ]
```

Step 10: compare again, not equal, same process with step 3, move j to `j = array[j-1]`

```
j i
a a b a a b a a a
[0 1 0 1 2 3 4 5 ]
```

Step 11: compare again, not equal, same process with step 3

```
j i
a a b a a b a a a
[0 1 0 1 2 3 4 5 ]
```

Step 12: compare again, equal, same process with step 2

```
j i
a a b a a b a a a
[0 1 0 1 2 3 4 5 2]
```

So, loop is done. As you can see, every step we calcuate the longest happy prefix of the current string. For every iteration, we don't need to calculate from the beginning, we can use the previous result to calculate current one. So time complexity is `O(n)`

.

Let implement this process in code.

```
function longestPrefix(s: string): string {
let i = 1;
let j = 0;
let lps = Array.from({ length: s.length }, _ => 0);
while (i < s.length) {
if (s.charAt(i) === s.charAt(j)) {
lps[i++] = ++j;
} else {
if (j === 0) {
lps[i++] = 0;
} else {
j = lps[j - 1];
}
}
}
return s.slice(0, j)
};
```

]]>If we want to use counting sort, we need to know the bound of numbers. Radix sort use 10 as the bound, and sort numbers in each digits by counting sort.

For example, Say we have an array `[75, 45, 9, 123]`

. We first use counting sort on least digit, which is `[5,5,9,3]`

, then we get array `[123, 75, 45, 9]`

. Then use counting sort again on second digit, which is `[2,7,4,0]`

, then we get `[9, 123, 45, 75]`

. Note that if that digit is empty, then use 0. Then again, until to the last digit.

```
[75, 45, 9, 123]
[123, 75, 45, 9]
[9, 123, 45, 75]
[9, 45, 75, 123]
```

So basically, radix sort is just a for loop with a counting sort inside. If you already know how the counting sort works, then it is easy. Let's see the code.

```
function radixSort(nums: number[]) {
let exp = 1;
const aux = Array.from({ length: nums.length }, _ => 0);
const getIdx = (i: number) => Math.trunc(nums[i] / exp) % 10;
let maxVal = nums[0];
for (let i = 1; i < nums.length; i++) {
if (nums[i] > maxVal) {
maxVal = nums[i];
}
}
let times = Math.floor(Math.log10(maxVal)) + 1;
while (times-- > 0) {
// basic counting sort process
const count: number[] = Array.from({ length: 10 }, _ => 0);
// count table
for (let i = 0; i < nums.length; i++) {
count[getIdx(i)] += 1;
}
// prefix sum
for (let i = 1; i < count.length; i++) {
count[i] += count[i - 1];
}
// from back to front
for (let i = nums.length - 1; i >= 0; i--) {
aux[--count[getIdx(i)]] = nums[i];
}
for (let i = 0; i < nums.length; i++) {
nums[i] = aux[i];
}
// next radix
exp *= 10;
}
}
```

Now we know the algorithm, let's solve the leetcode Maximum Gap problem with it.

```
function maximumGap(nums: number[]): number {
if (nums.length < 2) return 0;
if (nums.length === 2) return Math.abs(nums[1] - nums[0]);
radixSort(nums);
let maxGap = 0;
for (let i = 0; i < nums.length - 1; i++) {
const currentGap = nums[i + 1] - nums[i];
if (currentGap > maxGap) {
maxGap = currentGap;
}
}
return maxGap;
};
```

]]>We know that all things in computer are bits. If we want to use bits to express unsigned interger, we can just use the binary format to interpret bits into integers. For example, if we have 4 bits, then it may looks like below table.

```
0 0 0 0 => 0
0 0 0 1 => 1
0 0 1 0 => 2
0 0 1 1 => 3
0 1 0 0 => 4
0 1 0 1 => 5
0 1 1 0 => 6
0 1 1 1 => 7
...
```

But how about negative values? We can use the first bit as a sign, with 0 as positive, 1 as negative. So table may looks like below.

```
1 1 1 1 => -7
1 1 1 0 => -6
1 1 0 1 => -5
1 1 0 0 => -4
1 0 1 1 => -3
1 0 1 0 => -2
1 0 0 1 => -1
1 0 0 0 => -0
0 0 0 0 => 0
0 0 0 1 => 1
0 0 1 0 => 2
0 0 1 1 => 3
0 1 0 0 => 4
0 1 0 1 => 5
0 1 1 0 => 6
0 1 1 1 => 7
```

OK, it looks good. Let's do some math. How about `-3 + 3`

?

```
1011 <= -3
0011 <= 3
-----
1110 <= -6
```

This math give us the answer `-6`

, which is definitely wrong.

So a simple sign bit is not enough, we need to make some improvement.

Let's try to inverse value bits for negative values. Then the table becomes below.

```
1 0 0 0 => -7
1 0 0 1 => -6
1 0 1 0 => -5
1 0 1 1 => -4
1 1 0 0 => -3
1 1 0 1 => -2
1 1 1 0 => -1
1 1 1 1 => -0
0 0 0 0 => 0
0 0 0 1 => 1
0 0 1 0 => 2
0 0 1 1 => 3
0 1 0 0 => 4
0 1 0 1 => 5
0 1 1 0 => 6
0 1 1 1 => 7
```

With this new table, let's do this math again.

```
1100 <= -3
0011 <= 3
-----
1111 <= -0
```

The answer is `-0`

, this is close.

Now let's do the last step of two's complement, add all negative values with value 1. Then the table should becomes below.

```
1 0 0 0 => -8
1 0 0 1 => -7
1 0 1 0 => -6
1 0 1 1 => -5
1 1 0 0 => -4
1 1 0 1 => -3
1 1 1 0 => -2
1 1 1 1 => -1
0 0 0 0 => 0
0 0 0 1 => 1
0 0 1 0 => 2
0 0 1 1 => 3
0 1 0 0 => 4
0 1 0 1 => 5
0 1 1 0 => 6
0 1 1 1 => 7
```

Note that adding only applys to the bits part, the value it represents is not changed. And `1111`

plus 1 becomes `1000`

, and we use it to represent `-8`

.

Now let's do the math again.

```
1101 <= -3
0011 <= 3
-----
10000 <= 0
```

Overflow bits should be discarded. Then we finally get the right answer.

That's all the process of two's complement. We can also see this process in terminal(JavaScript).

```
> ~3
-4
> ~3 + 1
-3
```

]]>We all know that, in computer everything stored in bits, and bits are limited. Normally, we could use 16/32/64/128 or more bits to express a number. Say we decide to use 32 bits, then what? How can we use this 32 bits to express numbers?

Then comes the IEEE 754, which is a standard to express floating numbers. We could follow this standard, and implement the encoding and decoding from raw bits to target numbers. In this article, let's try to follow this standard and build a 32 bits floating point encoder and decoder by hand.

Before we get to the actual implementation, let consider the classic question `0.1 + 0.2 = 0.30000000000000004`

. Why this could happen? Is this a flaw? Actually no, this is just the way it works. Image how many number beween 0 and 1? Yes, Infinite. But how many value we can express in only 32 bits? Its only `Math.pow(2, 32)`

. So when we try to use this limited resources to express infinite values, we just unable to do it precisely. So floating point values in computers is just an approximation to the actual value. That is why the classic question happens. We will write the encoding/decoding code soon, then you will know what is the actual meaning of approximation.

IEEE 754 use scientific notation to express numbers. Basic formula looks like below.

```
sign * 2^exponent * (1+mantissa)
```

You can see there are 3 key parts in this formula.

Sign is a 1 bit value, which is used to indicate if the number is positive.

Exponent is a variable to indicate range. Note that it is 2 based. Let's see some range to get feel of it.

```
exponent value
...
-8 1/256
-7 1/128
-6 1/64
-5 1/32
-4 1/16
-3 1/8
-2 1/4
-1 1/2
0 1
1 2
2 4
3 8
4 16
5 32
6 64
7 128
8 256
...
```

As you can see, negative exponent can be used to express small number, and positive exponent can be used to express big number.

Mantissa is a variable to express precision. Before, we have used exponent to fit a number in a range, and then we can use this mantissa to express the precision.

Now we know the formula. Let's take a example `12.23`

to see how to express it in IEEE 754 format in 32 bits step by step.

According to the standard, we need to use 1 bit to express sign, 8 bits to express exponent, and 23 bits to express mantissa.

```
const EXP_BITS = 8;
const MANTISSA_BITS = 23;
const NON_SIGN_BITS = EXP_BITS + MANTISSA_BITS;
```

First, the most easy part, we check if the number is positive, and store result in variable `sign`

.

```
const sign = Math.sign(n) === -1 ? 1 : 0;
```

Next, we need to search which range this number should fit in. Look at the above table, we know that `12.23`

is between `8`

to `16`

, so exponent range is `3`

and `4`

. We choose the lower one as the value of exponent. This step can be calculated using log operation.

```
const exponent = Math.floor(Math.log2(n));
```

Next, we need to calculate mantissa. We already know that the value is in range `[8-16]`

, precision is just a point in this range. We can think mantissa is a percentage above lower bound. For example, this point could be in `8 * percentage`

. So, how to calculate this percentage. This is easy. We know the lower and upper bound, we know actual value, we can just calculate the proportion as the percentage.

```
const lower = 2 ** exponent;
const upper = 2 ** (exponent + 1);
const percentage = (n - lower) / (upper - lower);
```

But percentage is not the actually value, we need to express it in binary format. Because we know we should use exactly 23 bits to express this part. So using same logic of proportion, we can convert percentage into a value.

```
const mantissa = MAX_MANTISSA_VALUE * percentage;
```

This `MAX_MANTISSA_VALUE`

is just the maximum value can be expressed in 23 bits.

```
const MAX_MANTISSA_VALUE = 2 ** MANTISSA_BITS;
```

Last thing about encoding is that, exponent can be negative, but there is no sign bit in exponent part. So we need to add a bias to exponent, to make it like from `[-n, n]`

to `[0, 2n]`

, so it can be expressed in positive interge. This is just a small trick, later we will subtrack this bias in decoding part.

```
const BIAS = Math.pow(2, EXP_BITS) / 2 - 1;
```

So, finally, we can encode all the above values in a variable in 32 bits.

```
(sign << NON_SIGN_BITS) | ((exponent + BIAS) << MANTISSA_BITS) | mantissa;
```

And the whole encoding code.

```
const EXP_BITS = 8;
const MANTISSA_BITS = 23;
const NON_SIGN_BITS = EXP_BITS + MANTISSA_BITS;
const BIAS = Math.pow(2, EXP_BITS) / 2 - 1;
const MAX_MANTISSA_VALUE = 2 ** MANTISSA_BITS;
const encode = n => {
const sign = Math.sign(n) === -1 ? 1 : 0;
n = Math.abs(n);
const exponent = Math.floor(Math.log2(n));
const lower = 2 ** exponent;
const upper = 2 ** (exponent + 1);
const percentage = (n - lower) / (upper - lower);
const mantissa = MAX_MANTISSA_VALUE * percentage;
return (sign << NON_SIGN_BITS) | ((exponent + BIAS) << MANTISSA_BITS) | mantissa;
};
```

Now let's do the decoding part.

First, we test the first bit to know the sign value.

```
const sign = (n >>> NON_SIGN_BITS);
```

Then we get the next 8 bits to know the exponent value.

```
const exponent = (n >>> MANTISSA_BITS) & ~(1 << EXP_BITS);
```

And then we get the least 23 bits to know mantissa value.

```
const mantissa = (n & ~(~0 << MANTISSA_BITS));
```

With mantissa, we can calculate percentage backwards.

```
const percentage = mantissa / MAX_MANTISSA_VALUE;
```

And then calculate final result.

```
(-1) ** sign * (1 + percentage) * 2 ** (exponent - BIAS);
```

Let's see the whole decoding part.

```
const decode = n => {
const sign = (n >>> NON_SIGN_BITS);
const exponent = (n >>> MANTISSA_BITS) & ~(1 << EXP_BITS);
const mantissa = (n & ~(~0 << MANTISSA_BITS));
const percentage = mantissa / MAX_MANTISSA_VALUE;
return (-1) ** sign * (1 + percentage) * 2 ** (exponent - BIAS);
};
```

Finally, we can test our encoding and decoding process.

```
const original = 0.1;
const encoded = encode(original);
const decoded = decode(encoded);
console.log({ original, encoded, decoded });
// { original: 0.1, encoded: 1036831948, decoded: 0.09999999403953552 }
```

Don't be surprised when you see the `09999999403953552`

. This is just the approximation I said in the beginning.

Lastly, this is just a toy code to show the idea of IEEE 754. Use it with causion.

]]>`+`

and `-`

to do addition and subtraction. Have you considered how to use bitwise operations to do these? In this article, let's explore some of them.
First, let's see how to do simple addition in 2 base in normal way.

```
3 + 5
11
101
----
1000 <= answer
```

We do it from right to left on every digits. Note that if current sum is bigger than the base, then a carry need to be stored to be used in next digit addition.

Now let's see how to do it using only bitwise operation.

First, calculate answer without considering carry.

```
11
101
----
110 <= answer without carry
```

This operation can be done by `a ^ b`

.

Then calculate carry(without considering previous carry).

```
11
101
----
001 <= carry
```

This operation can be done by `(a & b) << 1`

.

Do this process again, until carry is 0, then we can get the final result.

Let's see this process in code.

```
function add(a: number, b: number) {
while (b > 0) {
const answer = a ^ b;
const carry = (a & b) << 1;
a = answer;
b = carry;
}
return a;
}
console.log(add(3, 5));
```

Same as addition, let's first see how to do subtraction in 2 base.

```
5 - 3
101
- 11
------
010 <= answer
```

Remember that, if current digit is not enough to subtrack, then a borrow needed to be made from next digit.

Now let's see how to do is in bitwise operations.

First, calculate answer without considering borrow.

```
101
- 11
------
110 <= answer without considering borrow
```

This operation can be done by `a ^ b`

.

Then calculate borrow without considering previous borrow.

```
101
- 11
------
010 <= borrow
```

This operation can be done by `((~a) & b) << 1`

.

Then let answer subtrack borrow again, until borrow is 0, then we can get final result.

Let's see this process in code.

```
function subtrack(a: number, b: number) {
while(b > 0) {
const answer = a ^ b;
const borrow = ((~a) & b) << 1;
a = answer;
b = borrow;
}
return a;
}
console.log(subtrack(105, 3))
```

Now we can use this leetcode problem to test the above code.

```
function getSum(a: number, b: number): number {
let [x, y] = [Math.abs(a), Math.abs(b)];
if (x < y) {
// abs big one first
return getSum(b, a);
}
// consider negative
const sign = a > 0 ? 1 : -1;
if (a * b >= 0) {
return add(x, y) * sign;
} else {
return subtrack(x, y) * sign;
}
};
console.log(getSum(-14, 16))
```

]]>```
// in constructor
const re1 = new RegExp("pattern", "flags");
// in inline
const re2 = /pattern/g;
// multiple flag
const re3 = /pattern/gmi;
```

`i`

Make case insensitive.

```
> /p/.test("p")
true
> /p/.test("P")
false
> /p/i.test("P")
true
```

`g`

Looks for all matches.

```
> "aaabaaa".replace(/a/, "");
'aabaaa'
> "aaabaaa".replace(/a/g, "");
'b'
```

`s`

Enable dotall mode, which means dot `.`

could match newline character.

```
> /.bc/.test("abc")
true
> /.bc/.test("bbc")
true
> /.bc/.test("cbc")
true
> /.bc/.test("\nbc")
false
> /.bc/.test("\rbc")
false
> /.bc/s.test("\nbc")
true
> /.bc/s.test("\rbc")
true
```

`m`

Enable multiline mode, `^`

and `$`

not only match the beginning and end of the string, but also at start/end of line.

```
> let text = `1. line one.
... 2. line two.
... 3. line four.`;
> text.match(/^\d/g);
[ '1' ]
> text.match(/^\d/gm);
[ '1', '2', '3' ]
```

`y`

Make the search sticky. Flag `y`

is similiar to flag `g`

, but every next match should start exactly from last index.

Let's see an example. If there is no `g`

or `y`

flag, exec always return first match.

```
> let s = "aaba";
> let re = /a/;
> re.exec(s);
[ 'a', index: 0, input: 'aaba', groups: undefined ]
> re.exec(s);
[ 'a', index: 0, input: 'aaba', groups: undefined ]
> re.exec(s);
[ 'a', index: 0, input: 'aaba', groups: undefined ]
```

If we add flag `g`

, then every exec should start to search from lastIndex.

```
> let re = /a/g;
> re.exec(s);
[ 'a', index: 0, input: 'aaba', groups: undefined ]
> re.exec(s);
[ 'a', index: 1, input: 'aaba', groups: undefined ]
> re.exec(s);
[ 'a', index: 3, input: 'aaba', groups: undefined ]
> re.exec(s);
null
```

But if we use flag `y`

, every exec should match exactly start from the last index(last index start from 0).

```
> let re = /a/y;
> re.exec(s);
[ 'a', index: 0, input: 'aaba', groups: undefined ]
> re.exec(s);
[ 'a', index: 1, input: 'aaba', groups: undefined ]
> re.exec(s); // here, last a doesn't match
null
> re.exec("baaba"); // here, first a doesn't match
null
```

`u`

Enable full unicode support. The most useful usage I see is try to use `\p{...}`

to match unicode properties.

Every character in Unicode has a lot of properties. They describe what category the character belongs to. For example, we can use `sc`

to specify a language. In below example, we try to match japanese katakana.

```
> let re = /\p{sc=Kana}/u;
> re.test("abc")
false
> re.test("")
false
> re.test("")
false
> re.test("")
true
```

]]>For example, we can use the famous Least Significant Bit (LSB) algorithm to conceil information in a image file while ensuring that the difference is not visible to the naked eye.

specifically, say we have a png file, which consists of RGBA values. Each value is a 8-bit unsigned number ranging from 0-255. We can use the least significant bit of this value to save our information.

```
pixel values:
23, 42, 178, ...
express in 2 base:
00010111, 00101010, 10110010, ...
_______x, _______x, _______x, ...
```

In above example, don't change `_`

part, just use the least significant bit the `x`

part as a storage to save our secret data. Note that the first seven bits is not changed, we only use the last one bit. In this case, the data of this image is changed indeed, but each value is only changed by one. This tiny change of color should not be detected by naked eye.

This way the goal is achieved. Now let's see how to do this in JavaScript.

First, let's define the basic code flow for this.

```
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<canvas id="c1"></canvas>
<canvas id="c2"></canvas>
<script>
const c1 = document.getElementById("c1");
const c2 = document.getElementById("c2");
const ctx1 = c1.getContext("2d");
const ctx2 = c2.getContext("2d");
const secret = "";
const maxLen = 16; // secret buffer length, max bytes
function loadImg(src) {
return new Promise(resolve => {
const img = new Image();
img.onload = () => {
resolve(img);
};
img.src = src;
});
}
function encode(imgData, secretBuf) {
}
function decode(imgData) {
}
loadImg("./123.png").then(img => {
c1.width = img.width;
c1.height = img.height;
c2.width = img.width;
c2.height = img.height;
ctx1.drawImage(img, 0, 0);
const data = ctx1.getImageData(0, 0, img.width, img.height);
const encoder = new TextEncoder();
const secretBuf = encoder.encode(secret);
encode(data.data, secretBuf);
ctx2.putImageData(data, 0, 0);
const decodedSecretBuf = decode(data.data);
const decoder = new TextDecoder();
const decodedSecret = decoder.decode(secretBuf);
console.log({ decodedSecret });
})
</script>
</body>
```

As you can see, we define two canvas element, one for original image, one for the changed one. And we use the canvas api to get image data, the pixel values of the image. We also use the TextEncoder and TextDecoder to encode/decode secret message into UTF8 encoding binary format. What's left to do is implement the steganography encode/decode function.

To encode/decode easily, we define a simple scheme here. we use first 16 pixel values to express the length of the secret. Because each pixel can only hold 1 bit real data, so 16 pixel values can hold a 16 bits unsigned value, which can express 65535 bits of secret.

```
bit
0 1 2 3 ..., 16 - ....
[data length] [ data ]
```

Now comes the encode/decode function. I made a lot of comment, so it should be easy to read.

```
function encode(imgData, secretBuf) {
// check if number of pixels enough to hold secret data
if ((maxLen + secretBuf.length * 8) > imgData.length) {
throw new Error("not enough image space to encode");
}
// write secret length
const secretBufBitsLen = secretBuf.length * 8;
for (let i = 0; i < maxLen; i++) {
// clear least significant bit
imgData[i] &= 0b111111110;
// set it
imgData[i] |= ((secretBufBitsLen >> (maxLen - i - 1)) & 1);
}
// write secret data
let i = maxLen; // pixel index
for (const byte of secretBuf) {
for (let j = 7; j >= 0; j--) {
// clear least significant bit
imgData[i] &= 0b111111110;
// set it
imgData[i] |= ((byte >> j) & 1);
i += 1;
}
}
}
function decode(imgData) {
// read secret length
let secretBufBitsLen = 0;
for (let i = 0; i < maxLen; i++) {
secretBufBitsLen |= (imgData[i] & 1) << (maxLen - i - 1);
}
// read secret data
let secretBuf = new Uint8Array(secretBufBitsLen / 8);
for (let i = maxLen; i < maxLen + secretBufBitsLen; i++) {
const j = Math.floor((i - maxLen) / 8);
const k = 7 - ((i - maxLen) % 8);
secretBuf[j] |= ((imgData[i] & 1) << k);
}
return secretBuf;
}
```

Lastly, run above code in browser. You should see the two images in page and decoded result in console.

]]>Base64 is an algorithm to encode binary data by only 64 characters(plus `=`

as a placeholder). Let's first see how the algorithm works and them implement it from scratch.

Say we want to encode string `ab`

into base64 string.

First, let encode this string into UTF8 encoding binary data first.

```
ab
=> [97, 98]
```

Then we express it in binary format.

```
[97, 98]
=> [01100001, 01100010]
```

Then we split bits, each 6 bits into one group. Note that here, if the last group donesn't has enough 6 bits, just append 0's at the end.

```
[01100001, 01100010]
=> [011000, 010110, 001000]
```

Then we make every element as a valid uint8 value by padding 2 zeros from element's top.

```
[011000, 010110, 001000]
=> [00011000, 00010110, 00001000]
```

Let's see it now in 10 base format.

```
[00011000, 00010110, 00001000]
=> [24, 22, 8]
```

Next, we map each value with a table to get the corresponding characters. The table is as below.

```
// used for encode
const table = [
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+', '/'
];
// used for decode
const reverseTable = table.reduce((pre: Record<string, number>, cur: string, i: number) => {
pre[cur] = i;
return pre;
}, {});
```

```
// value as table's index
[24, 22, 8]
=> [Y, W, I]
```

At last, we append `=`

at the end according to the value of `original binary array's length % 3`

. If the value is 2, then append `=`

. If the value is 1, then append `==`

.

That's all of it. Simple.

Let's implement the process in code.

```
function encode(text: string): string {
const before = new TextEncoder().encode(text);
const after = new Uint8Array(Math.ceil(before.length * 8 / 6));
let i = 0; // index of before
let j = 7; // index of current bit(all bit)
let x = 0; // index of after
let y = 5; // index of current bit(right 6 bit)
// bit index
// 76543210
// 00000000
while (true) {
// current j, need to be y
const diff = j - y;
let v = (before[i] & (1 << j));
if (diff >= 0) {
v >>= diff;
} else {
v <<= -1 * diff;
}
after[x] |= v;
if (j > 0) {
j -= 1;
} else {
if (i < before.length - 1) {
i += 1;
j = 7;
} else {
break;
}
}
if (y > 0) {
y -= 1;
} else {
x += 1;
y = 5;
}
}
let result = [...after].map(i => table[i]);
const remainder = before.length % 3;
if (remainder === 2) {
result.push("==");
} else if (remainder === 1) {
result.push("=");
}
return result.join("");
}
function decode(text: string): string {
let result = [...text.replace(/=+$/, "")];
let after = new Uint8Array(result.map(char => reverseTable[char]));
let before = new Uint8Array(Math.floor(after.length * 6 / 8));
let i = 0; // index of before
let j = 7; // index of current bit(all bit)
let x = 0; // index of after
let y = 5; // index of current bit(right 6 bit)
// bit index
// 76543210
// 00000000
while (true) {
// current y, need to be j
let v = (after[x] & (1 << y));
const diff = y - j;
if (diff >= 0) {
v >>= diff;
} else {
v <<= -1 * diff;
}
before[i] |= v;
if (j > 0) {
j -= 1;
} else {
i += 1;
j = 7;
}
if (y > 0) {
y -= 1;
} else {
if (x < after.length - 1) {
x += 1;
y = 5;
} else {
break;
}
}
}
return new TextDecoder().decode(before);
}
```

Lastly, make some tests.

```
const text1 = "ab";
const encoded1 = encode(text1);
const decoded1 = decode(encoded1);
console.log({ text1, encoded1, decoded1 }, text1 === decoded1);
const text2 = "";
const encoded2 = encode(text2);
const decoded2 = decode(encoded2);
console.log({ text2, encoded2, decoded2 }, text2 === decoded2);
const text3 = "";
const encoded3 = encode(text3);
const decoded3 = decode(encoded3);
console.log({ text3, encoded3, decoded3 }, text3 === decoded3);
```

And the result.

```
{ text1: "ab", encoded1: "YWI==", decoded1: "ab" } true
{ text2: "", encoded2: "44GT", decoded2: "" } true
{ text3: "", encoded3: "6YCf5a+56KGo", decoded3: "" } true
```

]]>Let's use the leetcode problem Implement strStr() as a test case. What we need to do is to find the `needle`

string in `haystack`

string.

Say the `haystack`

is `abcdefg`

and the `needle`

is `cde`

.

Let's first see the brute force way to do this. To brute force it, we need to iterate the haystack string and compare part of it with needle every time. Its process like below.

```
haystack: abcdefg
needle: cde
abcdefg
abc => cde
bcd => cde
cde => cde => match return
def => cde
efg => cde
```

As you can see, if the haystack's length is m, and the needle's length is n, then time complexity should be `O(m*n)`

.

In the brute force approach, in every iteration, we need to iterate the needle string again to compare it with part of haystack string. The idea of Rabin Karp Algorithm is to make this part more efficient by using the idea of hash.

Imagine we don't need to compare the needle with the part of the haystack every time, we just compare the hash of them, then the process should be way faster.

```
hash(needle) === hash(haystack.slice(0, needle.length))
```

Only hash them is not enough, to calculate the hash, we still need to loop the length of needle every time. The time complexity is still the same.

```
haystack: abcdefg
hash(abc)
hash(bcd)
hash(cde)
hash(def)
hash(efg)
```

So the next idea is to using rolling hash. The idea is if we could design a special hash function, which could use the previous hash to calculate current hash, then we can reduce the hash calculation time complexity from `O(n)`

to `O(1)`

.

To show the idea of rolling hash, let use a very simple rolling hash function first.

First, we map every character to a number, say a is 1, b is 2 and so on. Then when just make the sum of values as the hash values.

```
1 2 3 4 5 6 7 ... 26
a b c d e f g ... z
hash(abc) => a+b+c => 1+2+3
hash(bcd) => b+c+d => 2+3+4
...
```

This simple hash function has a special feature: we can calcuate the next hash easily based the previous one.

```
hash(abc) => a+b+c => 1+2+3
hash(bcd) => b+c+d => 2+3+4
hash(bcd) = hash(abc) - a + d
```

So now the time complexity of comparison part becomes `O(1)`

. Does it means that the whole time complexity becomes `O(m)`

? Actually, the answer is maybe. As you may know about the hash function, there is a concept of hash collision. Hash collision means that there are some cases that even the hashes are equal, the actual two strings may not be equal. Take the above simple sum hash function as an example, `hash(abc)`

should have the same hash value with `hash(bca)`

. So in this case, hash collision happens. When it happens, we need to compare these two strings one character by one character again.

So in best case, the time complexity is `O(m)`

and in worse case, the time complexity becomes `O(m*n)`

again.

Before we move on, let's see the code using this simple sum hash function to solve the problem.

```
function strStr(haystack: string, needle: string): number {
if (needle.length > haystack.length) return -1;
const base = "a".charCodeAt(0) - 1;
let needleHash: number = 0;
for (let i = 0; i < needle.length; i++) {
needleHash += (needle.charCodeAt(i) - base);
}
let haystackHash: number = 0;
for (let i = 0; i < haystack.length; i++) {
haystackHash += (haystack.charCodeAt(i) - base);
if (i >= needle.length) {
haystackHash -= (haystack.charCodeAt(i - needle.length) - base);
}
// if hash equals, check every character again
if (needleHash === haystackHash) {
let isEqual = true;
let start = i - needle.length + 1;
for (let j = 0; j < needle.length; j++) {
if (haystack.charCodeAt(start + j) !== needle.charCodeAt(j)) {
isEqual = false;
break;
}
}
if (isEqual) return start;
}
}
return -1;
};
```

Now you may thinking, if we could design a more sophisticated hash function, which reduce hash collision, then we can make this algorithm's time complexity close to `O(m)`

.

One popular working hash function is the polynomial rolling hash. The idea is, not just sum all values, but make every character has itw one weight. Let's see a example below.

```
hash(abc) => a*26^2 + b*26^1 + c*26^0
```

As you can see, because we have 26 unique characters(a-z), so make the weight 26. Then make the every character have different weights according to its order. In this way, the hash collision should be reduced substantially.

Next thing we need to know how to do rolling hash using this hash function. Still, let's see an example.

```
hash(abc) => a*26^2 + b*26^1 + c*26^0
hash(bcd) => b*26^2 + c*26^1 + d*26^0
So
hash(bcd) = (hash(abc) - a*26^2) * 26 + d*26^0
```

As you can see, we can do rolling hash easily with this hash function too. Let's see this in code.

```
function strStr(haystack: string, needle: string): number {
if (needle.length > haystack.length) return -1;
const base = "a".charCodeAt(0) - 1;
let needleHash: number = 0;
for (let i = 0; i < needle.length; i++) {
needleHash *= 26;
needleHash += needle.charCodeAt(i) - base;
}
let haystackHash: number = 0;
for (let i = 0; i < haystack.length; i++) {
if (i >= needle.length) {
haystackHash -= (haystack.charCodeAt(i - needle.length) - base) * Math.pow(26, needle.length - 1);
}
haystackHash *= 26;
haystackHash += (haystack.charCodeAt(i) - base);
if (haystackHash === needleHash) return i - needle.length + 1;
}
return -1;
};
```

However, there is still one problem left. As you can see, there is a lot multiplication above. This may cause number overflow. So normally, we should apply modulo operation to every step to avoid overflow. Applying modulo operation with rolling hash requires some mathematical derivation. Refer to my previous article Modulo Operation, if it helps.

```
function strStr(haystack: string, needle: string): number {
if (needle.length > haystack.length) return -1;
const base = "a".charCodeAt(0) - 1;
// const mod = Math.pow(10, 9) + 7; // big mod, less collision
const mod = 113;
let needleHash: number = 0;
for (let i = 0; i < needle.length; i++) {
// apply mod for every step
needleHash = ((needleHash * 26) % mod + (needle.charCodeAt(i) - base)) % mod;
}
let haystackHash: number = 0;
for (let i = 0; i < haystack.length; i++) {
// subtract leading character
if (i >= needle.length) {
// apply mod for every step
haystackHash -= (((haystack.charCodeAt(i - needle.length) - base) * Math.pow(26, needle.length - 1)) % mod);
}
// apply mod for every step
haystackHash = ((haystackHash * 26) % mod + (haystack.charCodeAt(i) - base)) % mod
// here, hash may become negative, make it positive
if (haystackHash < 0) {
haystackHash += mod;
}
// hash equals, compare character one by one in case of hash collision
if (haystackHash === needleHash) {
let isEqual = true;
let start = i - needle.length + 1;
for (let j = 0; j < needle.length; j++) {
if (haystack.charCodeAt(start + j) !== needle.charCodeAt(j)) {
isEqual = false;
break;
}
}
if (isEqual) return start;
}
}
return -1;
};
```

]]>```
5 % 2 => 1
```

This is an example of modulo operation. 5 is called dividend, 2 is called divisor and the result 1 is called remainder.

In JavaScript, we can do modulo operation as below.

```
> 5 % 3
2
> -5 % 3
-2
> 0 % 3
0
> 3 % 0
NaN
```

Sometimes, we may use modulo operations in various complicated arithmetic operations. So it is important to know some properties of modulo operations. Let's explore some mostly used ones.

`(a % n) % n === a % n`

```
> (5 % 2) % 2 === 5 % 2
true
```

`(n ^ x) % n === 0`

```
> Math.pow(5,3) % 5
0
```

`((-a % n) + (a % n)) % n === 0`

```
> ((-13 % 3) + (13 % 3)) % 3 === 0
true
```

`(a + b) % n === ((a % n) + (b % n)) % n`

```
> (3 + 5) % 3 === ((3 % 3) + (5 % 3)) % 3
true
```

`(a * b) % n === ((a % n) * (b % n)) % n`

```
> (3 * 7) % 2 === ((3 % 2) * (7 % 2)) % 2
true
```

]]>Monotonic stack is special kind of stack, in which elements are placed in monotonic order.

For example, there is monotonic increasing stack, which means elements are always in increasing order(from top to bottom). If the new elements larger then element currently on top, you need to pop the top element first and then push the new elements.

Below is simple example for a monotonic increasing stack.

```
class MonotonicStack {
private stack: number[];
constructor() {
this.stack = [];
}
push(v: number) {
while (this.stack.length > 0 && v > this.stack[this.stack.length - 1]) {
this.stack.pop();
}
this.stack.push(v);
}
pop(): number | undefined {
return this.stack.pop();
}
}
const monotonicStack = new MonotonicStack();
monotonicStack.push(1);// MonotonicStack { stack: [ 1 ] }
console.log(monotonicStack);
monotonicStack.push(3);// MonotonicStack { stack: [ 3 ] }
console.log(monotonicStack);
monotonicStack.push(5);// MonotonicStack { stack: [ 5 ] }
console.log(monotonicStack);
monotonicStack.push(4);// MonotonicStack { stack: [ 5, 4 ] }
console.log(monotonicStack);
monotonicStack.push(2);// MonotonicStack { stack: [ 5, 4, 2 ] }
console.log(monotonicStack);
monotonicStack.push(0);// MonotonicStack { stack: [ 5, 4, 2, 0 ] }
console.log(monotonicStack);
```

The problem is to find the number of days before a new temperature comes.

We can brute force it using 2 for loops. In this way, the time complexity is `O(n^2)`

.

Actually, this problem fits very well with the features of monotonic stack.

We can create a monotonic stack to save elements and its index. Every time a new temperature comes, if it's warmer, then we can compare it one by one with the elements in stack to get the result. If it's colder, then just push it into the stack, and wait for a new warmer day comes.

Below show a basic process for this method.

```
[30,40,20,10,50]
loop the array
index: 0, cur:30,
push, stack: [(30, 0)]
index: 1, cur:40,
cur>stack[top][0], pop (30,0), result[0]=1-0
stack.length === 0, push 40, stack: [(40,1)],
index: 2, cur:20,
cur<stack[top][0], push, stack: [(40,1),(20,2)]
index: 3, cur:10,
cur<stack[top][0], push, stack: [(40,1),(20,2),(10,3)]
index: 4, cur:50,
cur>stack[top][0], pop (10,3), result[3]=4-3
cur>stack[top][0], pop (20,2), result[2]=4-2
cur>stack[top][0], pop (40,1), result[1]=4-1
stack.length === 0, push, stack: [(50,4)]
last result, result[4] always 0
```

Now let's implement it in code.

```
function dailyTemperatures(temperatures: number[]): number[] {
let stack: number[][] = [];
let result: number[] = Array.from({length: temperatures.length}, _ => 0);
for (let i = 0; i< temperatures.length; i++) {
while(stack.length > 0 && temperatures[i] > stack[stack.length-1][0]) {
// warmer day comes, get results
const v = stack.pop() as number[];
result[v[1]] = i - v[1];
}
// colder day, save it for later
stack.push([temperatures[i], i])
}
return result;
};
const temperatures = [73,74,75,71,69,72,76,73];
console.log(dailyTemperatures(temperatures));
```

]]>