We could assume that the whole word could be the common one so we set prefix = ‘flower’
Then we would compare with the rest words and keep removing last character until prefix becomes empty (meaning no common substring was found) or until we have the common substring.
prefix
flower
flow
flight
flower
flower
flower
flower
flowe
flowe
flowe
flowe
flow
flow
flow
flow
flo
flo
flo
flo
fl
fl
fl
fl
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
var prefix = strs[0];
for(var i = 1; i < strs.length; i ++ ) {
while(strs[i].indexOf(prefix) != 0) {
prefix = prefix.substring(0, prefix.length - 1);
if(prefix == "")
return '';
}
}
return prefix;
};
what wejust did: – set up prefix to be the whole 1st word strs[0]
– compare prefix with the second word (strs[1]) and if there is no match, remove the last symbol and keep going until it finds match.
Complexity Analysis
Time complexity : O(S)O(S) , where S is the sum of all characters in all strings.In the worst case all nn strings are the same. The algorithm compares the string S1S1 with the other strings [S_2 \ldots S_n][S2…Sn] There are SS character comparisons, where SS is the sum of all characters in the input array.
Space complexity : O(1)O(1). We only used constant extra space.
Solution 2: Vertical scanning
Similar but optimized for cases like the one above where we have very short common substring, and we don’t want to scan the whole word.
prefix
flower
flow
flight
f
f
f
f
fl
fl
fl
fl
flo
flo
flo
flo
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function(strs) {
var prefix;
for(var i = 0; i < strs[0].length; i ++ ) {
var c = strs[0][i];
for(var j = 0; j < strs.length; j++) {
if(strs[j][i] != c) {
return strs[0].substring(0, i);
}
}
}
return strs[0];
};
what wejust did: – Iterate through the words like they are in column.
– compare each character (starting with the first one) between all words. When we find a mismatch, remove the last (mismatched) character and return truncates strs[0]
Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.
Symbol Value
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
For example, 2 is written as II in Roman numeral, just two one’s added together. 12 is written as XII, which is simply X + II. The number 27 is written as XXVII, which is XX + V + II.
Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:
I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer.
Example 1:
Input:
s = "III"
Output:
3
Example 2:
Input:
s = "IV"
Output:
4
Example 3:
Input:
s = "IX"
Output:
9
Example 4:
Input:
s = "LVIII"
Output:
58
Explanation:
L = 50, V= 5, III = 3.
Example 5:
Input:
s = "MCMXCIV"
Output:
1994
Explanation:
M = 1000, CM = 900, XC = 90 and IV = 4.
Constraints:
1 <= s.length <= 15
s contains only the characters ('I', 'V', 'X', 'L', 'C', 'D', 'M').
It is guaranteed that s is a valid roman numeral in the range [1, 3999].
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function(s) {
var len = s.length;
var i = 0;
var map = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
var sum = 0;
while(i < len) {
var currentVal = map[ s[i] ];
var nextVal = map[ s[i + 1] ];
if( currentVal < nextVal) {
sum += nextVal - currentVal;
i ++;
}
else {
sum += currentVal;
}
i ++;
}
return sum;
};
Solution 2: Left to right (or right to left) pass improved
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function(s) {
var len = s.length;
var i = 0;
var map = {
'I': 1,
'IV': 4,
'V': 5,
'IX': 9,
'X': 10,
'XL': 40,
'L': 50,
'XC': 90,
'C': 100,
'CD': 400,
'D': 500,
'CM': 900,
'M': 1000
}
var sum = 0;
while(i < len) {
var currentVal = map[ s[i] ];
var nextVal = map[ s[i + 1] ];
if( currentVal < nextVal) {
var sumbol = s[i] + s[i+1];
sum += map[sumbol];
i ++;
}
else {
sum += currentVal;
}
i ++;
}
return sum;
};
Solution3: Right to left pass
In the “subtraction” cases, such as XC, we’ve been updating our running sum as follows:
sum += value(C) - value(X)
However, notice that this is mathematically equivalent to the following:
sum += value(C)
sum -= value(X)
Utilizing this means that we can process one symbol each time we go around the main loop. We still need to determine whether or not our current symbol should be added or subtracted by looking at the neighbour though.
This way we could start from the most right symbol an initialize the sym with it, since every most right symbol will always be added to the sum.
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function(s) {
var len = s.length;
var i = len - 1;
var map = {
'I': 1,
'V': 5,
'X': 10,
'L': 50,
'C': 100,
'D': 500,
'M': 1000
}
var sum = map[ s[i] ];
i --;
while(i > -1) {
var currentVal = map[ s[i] ];
var prevVal = map[ s[i + 1] ];
if( currentVal < prevVal) {
sum -= currentVal;
}
else {
sum += currentVal;
}
i --;
}
return sum;
};
Given n non-negative integers a1, a2, ..., an, where each represents a point at coordinate (i, ai). n vertical lines are drawn such that the two endpoints of the line i is at (i, ai) and (i, 0). Find two lines, which, together with the x-axis forms a container, such that the container contains the most water.
Notice that you may not slant the container.
Example 1:
Input:
height = [1,8,6,2,5,4,8,3,7]
Output:
49
Explanation:
The above vertical lines are represented by array [1,8,6,2,5,4,8,3,7]. In this case, the max area of water (blue section) the container can contain is 49.
A better than brute force solution is to use a variation of “sliding doors” algorithm.
Let’s consider this case: [1,3,4,3]. The area with most water will be the one with highest height and length.
To find it we set up two pointers: one at position 0, and one at the end of the array. The amount of water that could be collected here is min(leftPointerValue, rightPointerValue) * length,
where length is rightPointer – leftPointer. Which is 4.
Now it’s clear that if rightPointerValue > leftPointerValue there is no point of keep moving rightPointer because we won’t get any bigger amount of water since it will always be limited by the leftPointerValue (height) and the length will always be smaller than the previous length.
So in this case we will move the leftPointer forward to evaluate the next case.
Here the amount of the water collected is min(leftPointerValue, rightPointerValue) * length which is min(3, 3) * 3 = 9.
Nex we continue evaluating all cases till leftPointer = rightPointer (length = 0), and we didn’t find bigger amount of water collected, so the answer we found on the second evaluation is the right answer: 9.
/**
* @param {number[]} height
* @return {number}
*/
var maxArea = function(height) {
var maxArea = 0;
var pLeft = 0;
var pRight = height.length - 1;
var len = pRight - pLeft;
while(len > 0) {
var pLeftVal = height[pLeft];
var pRightVal = height[pRight];
if(pLeftVal > pRightVal) {
maxArea = Math.max( len * pRightVal, maxArea );
pRight --;
}
else {
maxArea = Math.max( len * pLeftVal, maxArea );
pLeft ++;
}
len --;
}
return maxArea;
};
var height = [1,8,6,2,5,4,8,3,7];
console.log( maxArea(height) );
– Let’s imagine that you have a card component that you could show and hide with a button.
– When the component become visible an asynchronous function is called to get current time.
– Once the fetch is done, it will update the card showing current time.
The problem
– Let’s say that this asynchronous function is taking a few seconds to bring data back, and before it finishes the user decides to `hide` (or more appropriate thing to use is unmount) the card by clicking the button.
– when fetch is done, the asynchronous function will call setState to update the component that is no longer there and you will receive the nasty warning telling you that React can’t perform a React state update on an unmounted component.
And it makes perfect sense since the component and it’s DOM is not there any more.
The solution
– Use React refs to determine if the component is mounted or not.
– Line 5 – we added mounted param which is a reference to any DOM object in this component. If the component is not mounted mounted.current will return null
– Line 26 – we just add the actually reference tag to any DOM object that is constantly visible in our component. In most cases this is just the card wrapping div.
– Line 14 – we just check if the component exist or not before performing stateUpdate
Obviously we could also use the old fashion DOM way and use querySelector to check if the element is actually there but I guess useRefs is the more “React way” of doing this.
Jest sonar reporter is a plug-in that wi
jest-sonar-reporter is a custom results processor for Jest. The processor converts Jest’s output into Sonar’s generic test data format.
In other words we need this in order for SonarQube to to be able to process the result of Jest tests.
$ yarn add jest-sonar-reporter --dev
Let’s configure jest to use sonar-reporter and also to process and exclude of testing certain folders:
what we just did:
– lines 6 -14 we described which folders to be added in the coverage (“**/*.{js,jsx}”) and which to be excluded. (All that start with exclamation mark).
– line 18 describes where to create the report file, which sonarqube scanner will use.
what we just did:
– projectKey – is the unique identifier of the project.
– projectName – is the name of the project.
– sources – describes which folders to scan
– tests – where the scanner will look for test files.
– exclusions – which files should be excluded from coverage.
Create SonarQube project
Run sonar-scanner inside the root of the project:
$ sonar-scanner
Navigate to SonarQube web UI at the projects section, and you will see the new project created.
Integrating SonarQube quality tests with Jenkins
Before you continue make sure that you have Jenkins installed locally and is configured to run tests and deploy your project. Detailed instructions are found here:
Danger runs during your CI process, and gives teams the chance to automate common code review chores. It’s an automation checker against any opened pull requests.
Install danger JS
Navigate to the root of your folder and execute:
$ yarn add danger --dev; yarn danger init
yarn danger init
yarn run v1.22.4
$ /Users/toninichev/Cloud/workspace/nodeJS/Examples/Sparkjs/node_modules/.bin/danger init
Welcome to Danger Init - this will take you through setting up Danger for this project.
There are four main steps we need to do:
- [ ] Create a Dangerfile and add a few simple rules.
- [ ] Create a GitHub account for Danger to use, for messaging.
- [ ] Set up an access token for Danger.
- [ ] Set up Danger to run on your CI.
But before we start, we need one bit of information from you.
Is this is for an Open Source or private project?
[1] Open Source
[2] Private Repo
[0] CANCEL
1
## Step 1: Creating a starter Dangerfile
I've set up an example Dangerfile for you in this folder.
> cat /Users/toninichev/Cloud/workspace/nodeJS/Examples/Sparkjs/dangerfile.js
import {danger, warn} from 'danger'
// No PR is too small to include a description of why you made a change
if (danger.github.pr.body.length < 10) {
warn('Please include a description of your PR changes.');
}
// Request changes to src also include changes to tests.
const allFiles = danger.git.modified_files.concat(danger.git.created_files)
const hasAppChanges = allFiles.some(p => includes(p, 'src/'))
const hasTestChanges = allFiles.some(p => includes(p, '__tests__/'))
if (hasAppChanges && !hasTestChanges) {
warn('This PR does not include changes to tests, even though it affects app code.');
}
There's a collection of small, simple rules in here, but Danger is about being able to easily
iterate. The power comes from you having the ability to codify fixes for some of the problems
that come up in day to day programming. It can be difficult to try and see those from day 1.
If you'd like to investigate the file, and make some changes - I'll wait here,
press return when you're ready to move on...
↵
## Step 2: Creating a GitHub account
In order to get the most out of Danger, I'd recommend giving it the ability to post in
the code-review comment section.
https://github.com
IMO, it's best to do this by using the private mode of your browser.
Create an account like: SparkjsBot and don't forget a cool robot avatar too.
Here are great resources for creative-commons images of robots:
- https://www.flickr.com/search/?text=robot&license=2%2C3%2C4%2C5%2C6%2C9
- https://www.google.com/search?q=robot&tbs=sur:fmc&tbm=isch&tbo=u&source=univ&sa=X&ved=0ahUKEwjgy8-f95jLAhWI7hoKHV_UD00QsAQIMQ&biw=1265&bih=1359
Sidenote: Holding cmd ( ⌘ ) and double clicking a link will open it in your browser.
SparkjsBot does not need privileged access to your repo or org. This is because Danger will only
be writing comments, and you do not need special access for that.
Cool, please press return when you have your account ready (and you've verified the email...)
↵
## Step 3: Configuring a GitHub Personal Access Token
Here's the link, you should open this in the private session where you just created the new GitHub account
https://github.com/settings/tokens/new
For Open Source projects, I'd recommend giving the token the smallest scope possible.
This means only providing access to public_repo in the token.
This token limits Danger's abilities to just writing comments on OSS projects. We recommend
this because the token can quite easily be extracted from the environment via pull requests.
It is important that you do not store this token in your repository, as GitHub will
automatically revoke your token when pushed.
?, please press return when you have your token set up...
↵
## Add to CI
You need to expose a token called DANGER_GITHUB_API_TOKEN and the value is the GitHub Personal Access Token.
Depending on the CI system, this may need to be done on the machine (in the ~/.bashprofile) or in a web UI somewhere.
We have a guide for all supported CI systems on danger.systems:
http://danger.systems/js/guides/getting_started.html#setting-up-danger-to-run-on-your-ci
## Useful info
- One of the best ways to test out new rules as you build them is via bundle exec danger pr.
- You can have Danger output a lot of info via the --verbose option.
- You can look at the following Dangerfiles to get some more ideas:
* https://github.com/artsy/emission/blob/master/dangerfile.ts
* https://github.com/facebook/react-native/blob/master/bots/dangerfile.js
* https://github.com/apollographql/apollo-client/blob/master/config/dangerfile.ts
* https://github.com/styleguidist/react-styleguidist/blob/master/dangerfile.js
* https://github.com/storybooks/storybook/blob/master/dangerfile.js
* https://github.com/ReactiveX/rxjs/blob/master/dangerfile.js
?
And you're good to go. Danger is a collaboration between Orta Therox, Gem 'Danger' Maslen,
and every who has sent PRs.
If you like Danger, let others know. If you want to know more, follow @orta and @DangerSystems on Twitter.
If you don't like something about Danger, help us improve the project - it's all done on volunteer time! xxx
Remember: it's nice to be nice.
✨ Done in 1701.50s.
At the end this will create danger.js file in the root of your project.
Setup Github token
Create new Github token and give it “repo” access. This should be enough to allow the Github bot that will use it to post messages on pull requests.
Make sure that you copied the token and save it safely OUTSIDE OF THE PROJECT’S FOLDER, because you won’t be able to see the token again.
Also if you save it in the project’s folder, next time when you push the code Github will invalidate it cause this is considered a security breach.
import { fail, warn, message, markdown, danger } from "danger"
fail("Testing failure message");
warn("Testing warning");
message("Normal message");
markdown("*Markdown* is also **supported**");
const { additions = 0, deletions = 0 } = danger.github.pr;
message(`:tada: The PR added ${additions} and removed ${deletions} lines.`);
const modifiedMD = danger.git.modified_files.join("\n");
message(`Changed Files in this PR: \n ${modifiedMD} \n`);
Create pull request and test danger JS locally
Before we could do this, we have to export environment variable DANGER_GITHUB_API_TOKEN with the value equal to the tocen that we created in the previous chapter.
Windows, Linux or OSX machine running latest Java JDK or JRE.
Github account
You could fork the example project repo or you could use project of your own if you prefer.
if you want to set up a Webhook that will trigger automatic builds you will need Jenkins to be accessible from outside your network. You will have to set up port forwarding in your rauther.
Jenkins come in two versions: Long-term Support (LTS) and Weekly releases. If you want stable version choose (LTS)
Jenkins also require Java so make sure that you have the appropriate version installed. By the time I’m writing this it requires
On MAC OS brew install jenkins-lts
https://jenkins.io/download/lts/macos/
On CentOS
add Jenkins repo sudo rpm --import https://jenkins-ci.org/redhat/jenkins-ci.org.key
then install it. yum install jenkins
Then start the service brew services start jenkins-lts
Change default port (if needed, homebrew only)
Jenkins runs by default on port 8080, but I have another app running there so I had to change the default port.
Edit homebrew plist file as follows:
(replace 2.222.1 with the actual installed version)
Line 18: change the port to 8082.
Line 17: Change httpListenAddress from 127.0.0.1 to 0.0.0.0. This is necessary if you want to access Jenkins from Internet, outside of the internal network.
Pipeline ->Pipeline Script From SCM and put Git repository link.
Create Jenkins file with the pipeline steps
The whole pipeline should be wrapped in
pipeline {
}
A few words about pipeline syntax:
Agent is declared in the very beginning of the pipeline. This instructs Jenkins to allocate an executor (on a node) and workspace for the entire Pipeline.
An agent is typically a machine, or container, which connects to a Jenkins master and executes tasks when directed by the master.
Stage is part of Pipeline, and used for defining a conceptually distinct subset of the entire Pipeline, for example: “Build”, “Test”, and “Deploy”, which is used by many plugins to visualize or present Jenkins Pipeline status/progress.
Step A single task; fundamentally steps tell Jenkins what to do inside of a Pipeline or Project.
what we just did:
– line 2, told Jenkins that it could run this pipeline for any agent. Agent basically allows you to specify where the task is to be executed. It could be Docker, Node or any agent.
– line 6, we defined our stages: Cloning Git Repo, Install dependencies, Running Tests
– line 32: finally after all stage script passed we defined the post script to run the server.
I’m using pm2 (a process manager and launcher) for running the app so if you don’t have it installed you should install it using npm or yarn.
npm install pm2@latest -g
or
yarn global add pm2
Running the pipeline task
So now everything is set up, let’s test the pipeline. Navigate to the pipeline and from the vertical menu on the right select “build now”. If everything is good you should see a pipeline stages with progress bars filling out.
After the execution you could navigate to the log (build history in the right side -> select last job ->Console output)
There you could see a log of all stages executions including the snapshot tests
Test Suites: 2 passed, 2 total
Setting up Jenkins to listen to Github Webhook and trigger automatic builds on every commit
This is probably the best and the most tricky one to make it work. We are going to add Github Webhook that will make a post request to Jenkins every time when we push code change and this will trigger our pipeline and will rebuild the app and redeploy it. We are building so called continuous integration process. CI
Adding API key to the admin user.
Select the current (admin) user from the top right.
then on the left vertical menu choose “configure”.
Navigate to the “API Token” section and click “Add new token”
Important!!! Copy the token and save it somewhere safely because you won’t be able to see it again.
Navigate back to the pipeline that we created and click “configure” from the left vertical menu.
Scroll down to “Build Triggers” and check “Trigger builds remotely (e.g., from scripts)”
Paste the authentication token in the field and copy the example url below the text field where it says: “Use the following URL to trigger build remotely” We will need this to add it into Github webhook.
Click “save” on the bottom.
Setting up Github Webhook
Navigate to the example project in your Github space, select “settings” and “Webhooks”.
Click on “add webhook” and you will see this screen:
In the payload URL put the url that we copied from Jenkins -> Build Triggers above.
Important!!! Make sure that you replace ‘JENKINS_URL’ with the actual IP of the machine where Jenkins is running or the hostname if you set up one, and replace the token with the actual token that we generated for the ‘admin’ user.
On the dropdown below “Content type” select “application/json”
Leave “Secret” below empty.
Next on “Which events would like to trigger this webhook” is up to you, but for simplicity I just left the default “Just push event”
Make sure that “Active” is checked and click “Add webhook”
At this point if you commit some changes to the example project and push them a webhook should fire and do a POST request to your jenkins instance, notifying it that there are code changes and triggering the pipeline process … but when I did this and looked at the response I saw: “403 No valid crumb was included in the request“
This simply means that Jenkins require another token to be sent in the headers, to make sure that only authorised cities (Github in this example) will trigger the pipeline process.
This is the most obscure and unclear part of setting up Webhooks. I google it for quite some time and figured out that there is no way to send custom header parameters (like Jenkins-crumb) from Github so the only option was to disable this security feature … which I think is fine since the pipeline is already protected with API key that we added.
Disabling CSRF Protection in Jenkins
The CSRF protection settings lives in “Manage Jenkins” under “Configure Global Security” but as it looks like the lates Jenkins releases don’t have an option to disable this, so the only alternative was to do it through the groovy script.
Go to Manage Jenkins -> Script Console
and paste the code below in the console.
Line 5 tells enginx to intercept all requests / and proxy them from http://localhost:3000
If the request from example is /home Nginx will make request to http://localhost:3000/home
If for example we want to proxy only specific urls (let’s say only *.php) we could do this:
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
Note:m and n will be at most 100.
Example 1:
Input:
m = 3, n = 2
Output:
3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
1. Right -> Right -> Down
2. Right -> Down -> Right
3. Down -> Right -> Right
Since we can move only right or down on every cell in the first row we will have only one place from where we can come and this is the cell before. And same for the first vertical row.
Then after we figured out that there is only one way to reach each cell in the first row and the first column (which is from the cell before) we could start calculating possible ways to go to the next cells.
Let’s look at the cell in the second row and second column.There are actually two possible ways to go there: from the cell above, and the cell before, so 2 possible ways. (figure below).
The cell in the third column on the second row: same 1 way from the cell above, and from the cell before. But since there are already 2 ways to reach the cell before the total ways to reach this cell is: 1 + 2 = 3.
The solution:
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function(m, n) {
var memo = [];
for(var i=0;i < n; i ++) {
for(var j = 0; j < m; j ++) {
var index = (i * m) + j;
if(i == 0) {
memo[index] = 1;
}
else if(j == 0) {
memo[index] = 1;
}
else {
var up = index - m;
var left = index - 1;
memo[index] = memo[up] + memo[left];
}
}
}
return memo[memo.length - 1];
}
console.log(uniquePaths(7,3));
Unique paths with obstacles.
/**
* @param {number[][]} obstacleGrid
* @return {number}
*/
var uniquePathsWithObstacles = function(obstacleGrid) {
var m = obstacleGrid[0].length;
var n = obstacleGrid.length;
var row = 0;
if(obstacleGrid[0][0] == 1)
return 0;
var memo = [];
for(var i=0;i < n; i ++) {
for(var j = 0; j < m; j ++) {
var index = (i * m) + j;
if(i == 0) {
if(obstacleGrid[i][j] == 1 || (j > 0 && memo[index -1] == 0))
memo[index] = 0;
else
memo[index] = 1;
}
else if(j == 0) {
if(obstacleGrid[i][j] == 1 || (i > 0 && memo[index - m] == 0))
memo[index] = 0;
else
memo[index] = 1;
}
else {
var up = index - m;
var left = index - 1;
if(obstacleGrid[i][j] == 1)
memo[index] = 0;
else
memo[index] = memo[up] + memo[left];
}
row += memo[index] ? 0 : 1;
}
if(row == m)
return 0;
row = 0;
}
return memo[memo.length - 1];
};
var grid = [
[0,0,0],
[0,1,0],
[0,0,0]
];
console.log(uniquePathsWithObstacles(grid));
what we just did: – we calculated the length of the first list to be 5 and the second 6 (first and the second loop) – the third loop is doing two things: – first since the difference between the shorter and the longer list is 1 we move the cursor to the second element of the longer list (lines 59-61) – after we position the longer list cursor at the second element we could start comparing (line 64)
If we execute the function we will see this result:
long list, short list 0 4
long list, short list 1 1
long list, short list 8 8
And the third element is exactly where the intersection is.
Approach 3: Traverse both lists and when reaching the end of each one, move the pointer to the opposite list and traverse again till intersection is found.
Time complexity : O(m+n)O(m+n).
Space complexity : O(m)O(m) or O(n)O(n).
This basically is the same concept as in the example above, just written in a bit more elegant way.
function ListNode(val) {
this.val = val;
this.next = null;
}
headA = new ListNode(4);
headA.next = new ListNode(1);
headB = new ListNode(5);
headB.next = new ListNode(0);
headB.next.next = new ListNode(1);
headA.next.next = headB.next.next.next = new ListNode(8);
headB.next.next.next.next = headA.next.next.next = new ListNode(4);
headB.next.next.next.next.next = headA.next.next.next.next = new ListNode(5);
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let nodeA = headA;
let nodeB = headB;
let swapA = false;
let swapB = false;
var i = 0;
while(nodeA != null && nodeB!=null ) {
// node A
if(!swapA && nodeA.next == null) {
nodeA = headB;
swapA = true;
}
else {
nodeA = nodeA.next;
}
// node B
if(!swapB && nodeB.next == null) {
nodeB = headA;
swapB = true;
}
else {
nodeB = nodeB.next;
}
if(nodeA === nodeB)
return nodeA.val;
}
};
console.log (getIntersectionNode(headA, headB) );
what we just did:
– traverse listA and listB till we reach the end of each one (lines 47 and 55) .
– once we reach the end of each list we point the cursor to the opposite list (lines 43 and 51)
Approach 4: Hash Table
Traverse list A and store the address / reference to each node in a hash set. Then check every node bi in list B: if bi appears in the hash set, then bi is the intersection node.
Complexity Analysis
Time complexity : O(m+n)O(m+n).
Space complexity : O(m)O(m) or O(n)O(n).
function ListNode(val) {
this.val = val;
this.next = null;
}
// link-list A: [4,1,8,4,5]
// link-list B: [5,0,1,8,4,5]
headA = new ListNode(4);
headA.next = new ListNode(1);
headB = new ListNode(5);
headB.next = new ListNode(0);
headB.next.next = new ListNode(1);
headA.next.next = headB.next.next.next = new ListNode(8);
headB.next.next.next.next = headA.next.next.next = new ListNode(4);
headB.next.next.next.next.next = headA.next.next.next.next = new ListNode(5);
/**
* Definition for singly-linked list.
* function ListNode(val) {
* this.val = val;
* this.next = null;
* }
*/
/**
* @param {ListNode} headA
* @param {ListNode} headB
* @return {ListNode}
*/
var getIntersectionNode = function(headA, headB) {
let hashMap = {};
let node = headA;
while(node != null ) {
hashMap[node.val] = node;
node = node.next;
}
node = headB;
while(node != null) {
let val = node.val;
if(hashMap[val] == node) {
return val;
}
node = node.next;
}
};
console.log ("result: ", getIntersectionNode(headA, headB) );