Time Complexity of my 2 pointer algorithm - javascript

For the given problem below, what would be the time complexity of my solution (below the problem). I think it is not O(n^2), but I am not sure if it is O(n).
Problem: You are given two strings s and t. You can select any substring of string s and rearrange the characters of the selected substring. Determine the minimum length of the substring of s such that string t is a substring of the selected substring.
Signature int minLengthSubstring(String s, String t)
Input s and t are non-empty strings that contain less than 1,000,000 characters each
Output Return the minimum length of the substring of s. If it is not possible, return -1
Example s = "dcbefebce" t = "fd" output = 5
Explanation: Substring "dcbef" can be rearranged to "cfdeb", "cefdb", and so on. String t is a substring of "cfdeb". Thus, the minimum length required is 5.
My code:
function minLengthSubstring(s, t) {
// Write your code here
if(t.length > s.length) return -1;
let letters = new Map();
for(const tc of t) {
letters.set(tc, (letters.get(t) || 0) +1);
}
let min = Infinity;
let start = 0;
let i = 0;
let count = 0;
let map = new Map(letters);
while(i < s.length) {
if(map.has(s[i])) {
if(start === 0 && count === 0) start = i;
count++;
if(map.get(s[i]) === 1) map.delete(s[i])
else map.set(s[i], map.get(s[i]) -1);
if(count === t.length) {
min = Math.min(min, i-start+1);
map = new Map(letters);
count = 0;
start++;
i = start;
}
} else {
i++;
}
}
return min === Infinity ? -1 : min;
}
Thank you.

Related

i need to find the distance between two characters in string js. i have a solution but i can't understand the snippet of code related to if statement

The task was to write a function subLength() that takes 2 parameters, a string and a single character. The function should search the string for the two occurrences of the character and return the length between them including the 2 characters. If there are less than 2 or more than 2 occurrences of the character the function should return 0.
const subLength = (str, char) => {
let charCount = 0;
let len = -1;
for (let i=0; i<str.length; i++) {
if (str[i] == char) {
charCount++;
if (charCount > 2) {
return 0;
}
// could somebody explain why -1 is equal to len and then len is reassigned to i???
if (len == -1) {
len = i;
} else {
len = i - len + 1
}
}
}
if (charCount < 2) {
return 0;
}
return len;
};
dude there are other ways to do this.
see if my code helps you to understand any better :)
const subLength = (str, char) => {
let charCount = 0;
let letterFound = [];
let arr = str.split('');
for (let i = 0; i < arr.length; i++) {
if (arr[i] === char) {
letterFound.push(i);
charCount++;
}
}
let result = arr.slice(letterFound[0], letterFound[1]).length + 1;
if (charCount > 2 || charCount < 2) return 0;
return result;
}
console.log(subLength('saturday', 'a'));
in the first occurrence len= -1 so:
(len ==-1) turned to true;
and len is changed to i
so len=i;
in the second occurance len is not -1 so:
len = i - len -1;
in essence, in the above expression, len keeps the index of the first occurrence, and i has the index of second occurrence, so the difference will be, the difference between two occurrences, 'qweraq' : first occurrance: 0, second: 6. 6-0-1= 5 is difference;
This is how I manage to rewrite your code.
Hope this helps.
const subLength = (str, char) => {
const arr = str.split('');
let count = 0;
arr.forEach(letter => letter === char ? count++ : '')
const result = arr.some(letter => {
if (arr.indexOf(char) !== arr.lastIndexOf(char) && count == 2) {
return true
}
return false
})
return result ? Math.abs(arr.indexOf(char) - arr.lastIndexOf(char)) + 1 : 0
}
Whilst its possible to calculate the indexes and the count within a single loop, given the triviality I'd favor standard API methods for scanning. one could always optimize later if the application actually called for it.
First we convert the string to an array so that we have the ability to filter for matches to the input character, and derive the length.
Only if there are 2 occurrences do we calculate the distance between using the indexOf and lastIndexOf methods on string (note that these will only require a second full scan of the string if the two occurrences are consecutive).
Otherwise, the result should be 0.
const subLength = (str, chr) => {
const count = str.split('').filter(ltr => ltr === chr).length
if (count === 2) {
return (str.lastIndexOf(chr) - str.indexOf(chr)) + 1
}
return 0
}
console.log(subLength('asddfghvcba', 'a'))
console.log(subLength('asddfghvcba', 'x'))
console.log(subLength('aaaaaaaaaaa', 'a'))

Codwars: Array to single value +1

Given an array of integers of any length, return an array that has 1 added to the value represented by the array.
the array can't be empty
only non-negative, single digit integers are allowed
Return nil (or your language's equivalent) for invalid inputs.
Examples
For example the array [2, 3, 9] equals 239, adding one would return the array [2, 4, 0].
My code so far:
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return arr.some(e => typeof e !== 'number' || e < 0) ?
null : i
.toString()
.split('')
.map(e => parseInt(e));
};
It seems to pass most basic test however fails with larger inputs. Where have I gone wrong?
Just like you have converted the array into a number, you have to convert the number back into an array.
function upArray(arr){
let i = parseInt(arr.join('')) + 1;
return i.toString().split('').map(x => parseInt(x));
};
console.log(upArray([2,3,9]));
Your code won't work if the array length is greater than 100k...
Number type of javascript or any language is not enough big to handle it.
It's better if we calculate the last element with 1. If result is larger than nice ( < 10 ),
we continue to calculate next element with 1 and assign current value to 0. If result is smaller or equal 9, just assign the result to current and exit loop.
Then we print the final array as result:
pseudo code:
for i from: n-1:0
result = arr[i] + 1;
if(result < 10) :
arr[i] = result;
exit loop;// no need to continue calculate
else:
arr[i] = 0;
endif;
endfor;
You can join final array as string.
Here's probably the fastest solution (performance wise) - also there's no need to deal with BigInt, NaN, or Infinity:
function upArray(arr) {
if (!isInputIsNonEmptyArray(arr)) {
return null;
}
const isNumber = num => typeof num === 'number';
const isIntSingleDigit = num => Number.isInteger(num) && num >= 0 && num <10;
let resultArr = [];
let i = arr.length;
let num;
while (i-- > 0) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
if (num === 9) {
resultArr[i] = 0;
if (i === 0) { //means we're in the msb/left most digit, so we need to insert 1 to the left
resultArr.unshift(1);
break; //you can leave it out really, as the next check in the while will fail anyway
}
}
else {
resultArr[i] = num + 1; //No more + 1 should be made, just check for validity
//of the rest of the input and copy to the result arr
while (--i > -1) {
num = arr[i];
if (!isNumber(num) || !isIntSingleDigit(num)) {
return null;
}
resultArr[i] = arr[i];
}
break;
}
}
return resultArr;
function isInputIsNonEmptyArray(arr) {
return Array.isArray(arr) && arr.length > 0;
}
}
If the input arg is not an array or an empty array, or if you encounter invalid element during the main while loop you return null.
In the main while loop you go from the right most element (lsd), and add 1 to it (or insert 0 if the number is 9) up the the left most digit.
If a number which is less than 9 is incremented, no need to increment any more (this is the while loop in the else clause).

Javascript convert string to array with seperate letters and number

I have a string where I need to strip out the letters and the numbers. There will only be one number in the string.
So for example this string:
"AM12" I would like to split into this:
['A','M',12]
What is the most efficient way to do this? I was able to do it before with dashes in the string separating them (A-M-12) but was asked to remove the dashes.
Here is code I used for with dashes:
let arrUrl = myString.split('-');
Thanks.
You could use /\d+|./. It will match consecutive numbers or individual characters.
const split = str => str.match(/\d+|./g)
console.log(split("AM12"))
console.log(split("Catch22"))
If you need the number portion to be numeric in your resulting array, you could try something like this
let test = 'AM12'
let res = []
let num = ''
test.split('').forEach(e=>isNaN(e)?res.push(e):num+=e)
res.push(parseInt(num))
console.log(res)
You can scan the input string linearly, char by char, and keep track of any running number, also you should pay attention to the negative numbers.
The following snippet handles negative numbers and also multiple numbers in the same input.
function isDigit(char) {
return char >= "0" && char <= "9";
}
function split(input) {
const result = [];
// keep track of the running number if any
let runningNum = 0;
let isNum = false;
let isNegative = false;
for (let i = 0; i < input.length; i++) {
const ch = input[i];
if (isDigit(ch)) {
// check for negative value
if (i > 0 && input[i - 1] === "-") {
isNegative = true;
}
runningNum *= 10;
runningNum += (isNegative ? -1 : 1) * (ch - "0");
isNum = true;
} else {
// push previous running number if any
if (isNum) {
result.push(runningNum);
runningNum = 0; // reset
isNum = false;
isNegative = false;
}
// if current char is a "-" sign and the following char is a digit continue,
// if not then it's a hyphen
const isLastChar = i === input.length - 1;
if (!isLastChar && input[i] === "-" && isDigit(input[i + 1])) {
continue;
}
result.push(ch);
}
}
// in case the number at the end of the input string
if (isNum) {
result.push(runningNum);
}
return result;
}
const inputs = ["AM-12", "AM-12-30", "AM-12B30", "30", "a3b", "ab", "-", "-abc", "a-12-"];
for (let input of inputs) {
console.log(`"${input}": `, split(input));
}

How to "round" number, by putting zeros after the 2nd digit in javascript

I would like to "round" an integer number, by swapping all the digits after the 2nd digit to zeros. Additionally, if the number has only 1 digit, then don't do anything, and if the number has 2 digits, then swap the 2nd digit to a 0.
Example:
3 => 3
22 => 20
754 => 750
8912 => 8900
Can this be achieved without truncating the number as a string, and then rebuilding the number with zeros?
You don't need to truncate the number as a string, it can be easily achieved via mathematical calculation. Also, changing number to string and then doing any operation will be an added overhead which is not required in this case.
Refer the code below, it's quite straight forward.
Hope this helps.
function changeNumber(num){
if(Math.floor(num/10) == 0){
return num;
} else if(Math.floor(num/1000) == 0){
return Math.floor(num/10)*10;
}
else{
return Math.floor(num/100)*100
}
}
console.log(changeNumber(3));
console.log(changeNumber(22));
console.log(changeNumber(754));
console.log(changeNumber(8923));
That will work with every base-10 number.
All is about a simple math operation: number - [rest of (number / base-10 of number)]
function round(n) {
if(n < 10) return n;
var d = getTenBase(n.toString().length - 1);
return n - (n % (10 * d));
}
function getTenBase(l) {
var d = 1;
for(var i = 2; i < l; i++) {
d *= 10;
}
return d;
}
console.log(round(3));
console.log(round(22));
console.log(round(768));
console.log(round(1657));
you can just find length and first two character after that take zero with valid length and concat both
var str = '8912';
var n = str.length;
if(n == 1)
{
print(str);
} else if(n==2) {
var strFirst = str.substring(0,1);
var str2 = '0';
var res = strFirst.concat(str2);
} else if(n>2) {
var strFirst = str.substring(0,2);
var i;
var strsec ='0';
for (i = 0; i < n-3; i++) {
strsec += 0 ;
}
var res = strFirst.concat(strsec);
}
print(res);

Get Number of Decimal Places with Javascript

How would I calculate the number of decimal places (not digits) of a real number with Javascript?
function countDecimals(number) {
}
For example, given 245.395, it should return 3.
Like this:
var val = 37.435345;
var countDecimals = function(value) {
let text = value.toString()
// verify if number 0.000005 is represented as "5e-6"
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-');
let deg = parseInt(trail, 10);
return deg;
}
// count decimals for number in representation like "0.123456"
if (Math.floor(value) !== value) {
return value.toString().split(".")[1].length || 0;
}
return 0;
}
countDecimals(val);
The main idea is to convert a number to string and get the index of "."
var x = 13.251256;
var text = x.toString();
var index = text.indexOf(".");
alert(text.length - index - 1);
Here is a method that does not rely on converting anything to string:
function getDecimalPlaces(x,watchdog)
{
x = Math.abs(x);
watchdog = watchdog || 20;
var i = 0;
while (x % 1 > 0 && i < watchdog)
{
i++;
x = x*10;
}
return i;
}
Note that the count will not go beyond watchdog value (defaults to 20).
I tried some of the solutions in this thread but I have decided to build on them as I encountered some limitations. The version below can handle: string, double and whole integer input, it also ignores any insignificant zeros as was required for my application. Therefore 0.010000 would be counted as 2 decimal places. This is limited to 15 decimal places.
function countDecimals(decimal)
{
var num = parseFloat(decimal); // First convert to number to check if whole
if(Number.isInteger(num) === true)
{
return 0;
}
var text = num.toString(); // Convert back to string and check for "1e-8" numbers
if(text.indexOf('e-') > -1)
{
var [base, trail] = text.split('e-');
var deg = parseInt(trail, 10);
return deg;
}
else
{
var index = text.indexOf(".");
return text.length - index - 1; // Otherwise use simple string function to count
}
}
You can use a simple function that splits on the decimal place (if there is one) and counts the digits after that. Since the decimal place can be represented by '.' or ',' (or maybe some other character), you can test for that and use the appropriate one:
function countPlaces(num) {
var sep = String(23.32).match(/\D/)[0];
var b = String(num).split(sep);
return b[1]? b[1].length : 0;
}
console.log(countPlaces(2.343)); // 3
console.log(countPlaces(2.3)); // 1
console.log(countPlaces(343.0)); // 0
console.log(countPlaces(343)); // 0
Based on Gosha_Fighten's solution, for compatibility with integers:
function countPlaces(num) {
var text = num.toString();
var index = text.indexOf(".");
return index == -1 ? 0 : (text.length - index - 1);
}
based on LePatay's solution, also take care of the Scientific notation (ex: 3.7e-7) and with es6 syntax:
function countDecimals(num) {
let text = num.toString()
if (text.indexOf('e-') > -1) {
let [base, trail] = text.split('e-')
let elen = parseInt(trail, 10)
let idx = base.indexOf(".")
return idx == -1 ? 0 + elen : (base.length - idx - 1) + elen
}
let index = text.indexOf(".")
return index == -1 ? 0 : (text.length - index - 1)
}
var value = 888;
var valueLength = value.toString().length;

Categories

Resources