Sunday, August 08, 2021

Leetcode 128 Longest Consecutive Sequence

 In here, I would like to discuss the dynamic set in Leetcode 128 Longest Consecutive Sequence.

This is my solution: 

  • Put all numbers into set.
  • The find the first number of each sequence. The first number is the number without any previous number (n-1) in the set.
  • Loop through the next number (n+1). And find out the max count. (Remove the current number from set in order to iterate it again.)


var longestConsecutive = function(nums) {
    
    let set = new Set(nums);
    let maxLen = 0;
    function next(num) {
        if (set.has(num)) {
            //set.delete(num);
            return next(num + 1) + 1;
        } else {
            return 0;
        }
    }
    console.log(set);
    for (let num of nums) {
        //console.log(num);
        let pre = num - 1;
        if (!set.has(pre)) {
            let len = next(num+1) + 1;
            if (len > maxLen) {
                maxLen = len;
            }
        }
    }

    return maxLen;
};

 

The particular I would discuss is 

Remove the current number from set in order to iterate it again.

set.delete(num)

I would say that can be optimize performance. However, base on the leetcode submission result, dynamic changing set is actually a performance penalty.



 

 

 

 

 

 

Sunday, August 01, 2021

LeetCode, 200, Number of islands

To solve LeetCode question 200, there is already one good explanation of how to solve it.
The basic idea is to use tree traverse algorithm (dfs or bfs) to check the adjacent land.

Here is my Javascript solution:

/**
 * @param {character[][]} grid
 * @return {number}
 */
var numIslands = function(grid) {
    let count = 0;
    if (grid == null || grid.length === 0) {
        return 0;
    }

    let row = grid.length;
    let col = grid[0].length;
    function dfs(ij) {
        if (i > row - 1 || j > col -1 || i0 || j < 0) {
            return;
        }
        if (grid[i][j] === "1") {
            grid[i][j] = "0";
            dfs(i+1,j); //down
            dfs(i,j+1); //right
            dfs(i-1,j); //up
            dfs(i,j-1); //left
        }
    }

    for (let i=0i<rowi++) {
        for (let j=0j<colj++) {
            if (grid[i][j] === "1") {
                grid[i][j] = "0";
                dfs(i+1,j); //down
                dfs(i,j+1); //right
                dfs(i-1,j); //up
                dfs(i,j-1); //left
                count++;
            }
        }
    }

    return count;
};

var grid = [
    ["1","1","1","1","0"],
    ["1","1","0","1","0"],
    ["1","1","0","0","0"],
    ["0","0","0","0","0"]
];
console.log(result = numIslands(grid));
console.assert(result === 1);

grid = [
    ["1","1","0","0","0"],
    ["1","1","0","0","0"],
    ["0","0","1","0","0"],
    ["0","0","0","1","1"]
];
console.log(result = numIslands(grid));
console.assert(result === 3);
    
grid = [
    ["1","1","1"],
    ["0","1","0"],
    ["1","1","1"]
];
console.log(result = numIslands(grid));
console.assert(result === 1);



Thursday, July 22, 2021

Elasticsearch multiple indexes

Just another post of how to do multiple indexes search.


 

 



Wednesday, July 21, 2021

Postman to query Elasticsearch

To query elasticsearch result, that is use GET method with JSON data. Generally in REST API, we don't have body data in the GET method.

 



Tuesday, July 20, 2021

Upload React to AWS S3

Direct upload to AWS S3.

  • Create s3 bucket
  • Use Upload UI to upload the whole build folder.


  • In the Properties, scroll down to the bottom and the static web site hosting. Enable it. Amazon will assign a http subdomain.

  • Go to AWS cloudfront to create a new distribute.



  • Check New distribution.

     




Monday, July 19, 2021

Where is URL for AWS serverless function?

To find the serverless function URL, it's in the API Gateway.



Isomorphic Application

What is Isomorphic Application?

Firstable, what is Isomorphic?
To be simple, that is to have the same result from different approaches.

In this case, we may easy to understand what is Isomorphic Application.
That could be an application with same results from different approaches.
One particular case for the web page is a web page generated from both client side and server side.

In the old days, server side technology to be used to generate a web page. That just has a lot of payload, like full HTML syntax, JS, and CSS. Search engine can understand that if content is all embedded inside HTML markup.

For the modern single page application (SPA), a big huge chunk of JS is loaded ahead of data. This is the way to minimum to payload and improve the user experience.

There are few of Isomorphic applications. The most popular for these days is React w/Next.


 

In Next, the first request page will be generated from the server side. In this case, search engine can understand page semantics. For the rest of clicking/action, the client side js is used in order to take advantage SPA. If any page refresh, once again the server rendering is triggered.



 




Sunday, July 18, 2021

VSCode react shortcut

Install React code snippets extension to VSCode.

rcc->  == class component skeleton
rsc->  == stateless component skeleton
rsf->  == stateless named function skeleton

React render props with typescript

Apply static type to props with typescript.


import React from 'react';
import './App.css';

interface SectionProps {
  titlestring;
  render(): React.ReactNode;
}

const RenderPropsComponentReact.FC<SectionProps> = (props=> {
  return (
    <section>
      <h2>{props.title}</h2>
      {props.render()}
    </section>
  )
}

const SampleRenderProps1React.FC = () => {
  return (
    <RenderPropsComponent
      title="First Component"
      render = {()=> {
        return (
          <p>
            My first description
          </p>
        )
      }}
    />
  )
}

const SampleRenderProps2React.FC = () => {
  return (
    <RenderPropsComponent
      title="Second Component"
      render = {()=> {
        return (
          <p>
            Another description
          </p>
        )
      }}
    />
  )
}

const AppReact.FC = () => {
  return (
    <div className="app">
      <h1>Render Props Example</h1>
      <SampleRenderProps1 />
      <SampleRenderProps2 />
    </div>
  );
}

export default App


Result:



Saturday, July 17, 2021

React-admin with typeORM

1. React-admin missing X-total-count issue.
Need to fix it from server side response header in order to meet react-admin requirement.

To fix it, add extra response header: Category.tsx

 // GET ALL
  @Get('')
  public async getAll() {
    //return getCategory();
    let objs = await getCategory();
    if (Array.isArray(objs)) {
      let total = objs.length;
      // react-admin
      this.setHeader('Access-Control-Expose-Headers''X-Total-Count')
      this.setHeader('X-Total-Count'total+"")
    }
    return objs;
  }

 

2. Unable to update data if primary id also submit from data. typeORM only take ID from URL parameter, not from data.

[1] GET /api/categories?_end=10&_order=ASC&_sort=id&_start=0 200 1.591 ms - 390
[1] Caught Validation Error for /api/categories/undefined: { categoryId: { message: 'invalid float number', value: 'undefined' } }
[1] GET /api/categories/undefined 422 0.702 ms - 176

To fix it, tailor the submission data: category.router.ts

export const CategoryEdit = (props:any=>{
    //typeORM doesn't like to have id in the submission data again.
    const transform = (data:any=> {
        const {id, ...newData} = data;
        return newData;
    };
    return (
        <Edit title="Edit Category" {...props} transform={transform}>
            <SimpleForm>
                <TextInput source="name" />
            </SimpleForm>
        </Edit>
    )
};




Sunday, July 11, 2021

Leetcode 125. valid palindrome

Solution 1. Just parse string into character array. Then, use another loop to compare the character with head to middle and tail to middle.

var isPalindrome = function(s) {

    // parse string into valid character array
    let tmp = [];
    s.split("").forEach(c=>{
        c = c.toLowerCase();
        if (c>="a" && c<="z") {
            tmp.push(c);
        } else if (c>="0" && c<="9") {
            tmp.push(c);
        }
    });

    // compare characters from head to middle and tail to middle
    let len = tmp.length;
    let [i,j] = [0,len-1];
    while (i < j) {
        if (tmp[i]!==tmp[j]) {
            return false;
        }
        i++;
        j--;
    }

    return true;
};


Solution 2. Optimize it. Only one while loop with one head index and the other tail index. That's the way to stand out.

var isPalindrome = function(s) {

    function getChar(c) {
        let ret = "";
        c = c.toLowerCase();
        if ( 
            (c >= "0" && c <= "9") ||
            (c >= "a" && c <= "z")
        ) {
            return c;
        }
        return ret;
    }

    let len =s.length;
    let [headIdxtailIdx] = [0len-1];
    let headChar="";
    let tailChar="";
    while (headIdx < tailIdx) {

        //a character from head, return blank charater if not valid
        if (headChar.length===0) {
            headChar = getChar(s[headIdx]);
        }
        //a character from tail
        if (tailChar.length===0) {
            tailChar = getChar(s[tailIdx]);
        }

        //check if both head chacter and tail character valid
        //then check they are equal
        if (
            headChar.length===1 &&
            tailChar.length===1
        ) {
            if (headChar===tailChar) {
                headChar = "";
                tailChar = "";
                headIdx++;
                tailIdx--;
            } else {
                return false;
            }
        } else {
            // if not a valid character, move to next index
            if (headChar.length===0) {
                headIdx++;
            }
            if (tailChar.length===0) {
                tailIdx--;
            }
        }
    }

    return true;
};

Friday, July 09, 2021

The link in gitbook

 When I put my bookstore project in gitbook, there were few links actually pointing back to my github project. I just curious how the markdown parser work in gitbook.


Today, I finally realize that gitbook take a link as same site reference only if this link in the left side menu. That's it need to be in SUMMARY.md.


Sunday, July 04, 2021

GraphQL Mutation Input

Without input type

  type Mutation {
    createCategory(name:String!):Category
    updateCategory(id:ID, name:String!):Category
    deleteCategory(id:ID):String

    createPublisher(name:String!):Publisher
    updatePublisher(id:ID, name:String!):Publisher
    deletePublisher(id:ID):String

    createAuthor(name:String!):Author
    updateAuthor(id:ID, firstName:String, lastName:String):Author
    deleteAuthor(id:ID):String

    createBook(title:String!, categoryId:String, publisherId:String, authorId:String):Book
    updateBook(id:ID, title:String!, categoryId:String, publisherId:String, authorId:String):Book
    deleteBook(id:ID):String
  }



With input type

  input CategoryInput {
    name:String!
  }
  input PublisherInput {
    name:String!
  }
  input AuthorInput {
    firstName:String
    lastName:String
  }
  input BookInput {
    title:String!
    categoryId:String
    publisherId:String
    authorId:String
  }
  type Mutation {
    createCategory(input:CategoryInput):Category
    updateCategory(id:ID, input:CategoryInput):Category
    deleteCategory(id:ID):String

    createPublisher(input:PubliserInput):Publisher
    updatePublisher(id:ID, input:PubliserInput):Publisher
    deletePublisher(id:ID):String

    createAuthor(input:AuthorInput):Author
    updateAuthor(id:ID, input:AuthorInput):Author
    deleteAuthor(id:ID):String
    
    createBook(input:BookInput):Book
    updateBook(id:ID, input:BookInput):Book
    deleteBook(id:ID):String
  }  



Correct the input foreign Key as type Int. They are categoryId, publisherId, authorId in BookInput.

 

  input BookInput {
    title:String!
    categoryId:Int
    publisherId:Int
    authorId:Int
  }

 



Friday, July 02, 2021

Flat list

arr = [[1,2,3],[4,5,6],[7,8,9]]

In javascript:

let flatList = arr.flat()


In python, my trick is walrus operator:

flat_list = []
[flat_list:=flat_list+sub for sub in arr]

 




Check if a value in two diminsion array

arr = [[1,2,3],[4,5,6],[7,8,9]] 

 For javascript: 

var result = 1 in arr.flat(); 

For python: 

var result = any(1 in sub for sub in arr);

Website thumbnail in my linkedin profile

 Just checked in linkedin profile today. And found my website thumbnail missing again.


Then double checked my gatsby source. That's fine.

I use linkedin link inspector: https://www.linkedin.com/post-inspector/inspect/
to check my website again : https://www.linkedin.com/post-inspector/inspect/https:%2F%2Fccapeng.github.io
I did get some warning, but my profile thumbnail shown again.




 





Monday, June 28, 2021

Leetcode, 46 - Permutation

How to solve Leetcode, 46 permutation?

Let's see a easy way to solve with tree breadth first solution.

For example : [1, 2, 3]

The approach : take an item each time to insert into in between array.

1: [ [1] ]
   Insert the first number.

2: [ [1] ]
    ^   ^

   Insert 2 before and after 1.
   [[2,1],[1,2]]


3: 
    [
      [3,2,1],[2,3,1],[2,1,3],
      // place 3 around and between [ 2,1 ]
                                     ^ ^ ^
      [3,1,2],[1,3,2],[1,2,3]
      // place 3 around and between [ 1,2 ]
                                     ^ ^ ^
    ]

Hope this approach is easy to understand.

 

var permute = function(nums) {

  //init results with first numbers
  let results = [[nums[0]]];

  //loop through the rest of numbers
  for (let i = 1i<nums.length;i++) {
    let num = nums[i];
    let tmp=[];

    //loop through each item in the results
    for (let j=0;j<results.length;j++) {
      let result = results[j];

      //insert the current number around/in-between
      for (let k=0;k<=result.length;k++) {
        let head = result.slice(0,k);
        let tail = result.slice(k);
        tmp.push([...headnum, ...tail]);
      }
    }
    results = tmp;
  }
  return results;
};