Javascript: Is-SubArray returns false - javascript

I'm trying to run a program called IsSubArray. There are 2 input textboxes. One is called the big array and the other is called the sub array. The task is to check whether the values in sub array consecutively matches the numbers in big array. For example:
Array 1: 1,3,6,5,4
Array 2: 1,3,6 - true because 1,3 is matching with array 1.
Array 2: 1,6 - false because after 1, its 3 in array 1 not 6. It should match consecutively.
Array 2: 6,5,4 - true.
Array 2: 5,4,7 - false because is no number 7 after 4 in array 1.
But I am getting true for this last statement. I am unable to figure out why. I am just now learning algorithms.
Thanks in advance :)
function IsSubArray() {
inputArray1 = document.getElementById("inputText1").value.split(",");
inputArray2 = document.getElementById("inputText2").value.split(",");
var k = 0;
var msg = false;
for (j = 0; j < inputArray2.length - 1; j++) {
if (j > 0 && msg == false)
break;
//if (j > 0 && k == 0) {
// msg = false;
// break;
//}
for (i = 0; i < inputArray1.length - 1; i++) {
if (inputArray2[j] == inputArray1[i] && inputArray2[j + 1] != inputArray1[i + 1]) {
msg = false;
break;
}
else if (inputArray2[j] == inputArray1[i] && inputArray2[j + 1] == inputArray1[i + 1]) {
msg = true;
break;
}
//if (inputArray2[j] == inputArray1[i])
// k = 1;
}
}
document.getElementById("output").value = msg + " : LongArray: " + inputArray1 + " , ShortArray: " + inputArray2;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<input id="inputText1" type="text" />
<input id="inputText2" type="text" />
<br /><br />
<input id="IsSubArrayBtn" type="button" value="IsSubArray" onclick="IsSubArray()" />
<br /><br />
<input id="output" type="text" />
<script src="js/LogicalLoopings.js"></script>
</body>
</html>

The code seems overly complex. The general approach would be:
Find first element of subarray in array to get a starting point.
Verify that every element in subarray matches the following elements in array (at the starting point).
Repeat until there are no elements left to check.
Example implementation:
function contains(arr, subarray) {
const first = subarray[0];
// labeled loop so we can jump there easily
// find the "next" starting point for comparing the sequences
outer: for (let i = arr.indexOf(first); i > -1; i = arr.indexOf(first, i+1)) {
// When we find a starting point, compare the remaining elements in subarray
for (let j = 1; j < subarray.length; j++) {
if (arr[i+j] !== subarray[j]) {
// no need to continue checking the current sequence
// if one of the elements doesn't match
continue outer;
}
}
// if we made it through the inner loop then the sequences must be equal
return true;
}
// if we get here then `subarray` is not a sequence in `arr`
return false;
}
const arr = [1,3,6,5,4];
console.log(contains(arr, [1,3,6]));
console.log(contains(arr, [1,6]));
console.log(contains(arr, [6,5,4]));
console.log(contains(arr, [5,4,7]));
Array 2: 5,4,7 - false because is no number 7 after 4 in array 1. But I am getting true for this last statement. I am unable to figure out why.
You can add log statements to your code and see what actually happens. The problem is related to the fact that you are never iterating over all elements (i < inputArray1.length - 1) and that you are setting msg to true whenever two consecutive elements match.
The input is:
inputArray1 = [1,3,6,5,4]
// index i 0 1 2 3 4
inputArray2 = [5,4,7]
// index j 0 1 2
At some point you are comparing
inputArry2[0] == inputArry1[3] && inputArry2[1] == inputArry1[4]
// 5 == 5 && 4 == 4
which is true, so you set msg to true. Now the inner loop is done, because it stops when i === 3.
A new outer loop starts, where j = 1, so inputArry1[j] === 4. The first part of your if condition (inputArry2[j] == inputArry1[i]) is never fulfilled because i never has the value 4, so you are never comparing against the last element of inputArray1.
That means that msg is never assigned a new value and remains true.

check whether the values in sub array consecutively matches the numbers in big array
You can simplify the problem by using Array.join() and String.search():
const arr = [1, 3, 6, 5, 4]
/* test */
console.log(isSubArray(arr, [1,3,6])) // true
console.log(isSubArray(arr, [1,6])) // false
console.log(isSubArray(arr, [6,5,4])) // true
console.log(isSubArray(arr, [5,4,7])) // false
console.log(isSubArray(arr, [54])) // false
function isSubArray(original, guess) {
const a = original.join()
const b = guess.join()
return a.search(b) >= 0
}

Related

Fibonacci sequence generator not working for 1 or 2 as inputs but it works for the rest of the sequence?

Can someone explain to me why my fibonacciGenerator function doesn't work with this code? I understand why it works with the second code tho but I just don't get why the first one doesn't.
function fibonacciGenerator(n) {
if (n > 0) {
var fArray = [];
fArray.push(0);
if (n >= 2) {
fArray.push(1);
}
for (var i = 0; i < n; i++) {
fArray.push(fArray[i] + fArray[i + 1]);
}
console.log(fArray);
}
}
fibonacciGenerator(1);
fibonacciGenerator(2);
Second code working :
function fibonacciGenerator(n) {
if (n > 0) {
var fArray = [];
fArray.push(0);
if (n >= 2) {
fArray.push(1);
}
for (var i = 2; i < n; i++) {
fArray.push(fArray[i - 1] + fArray[i - 2]);
}
console.log(fArray);
}
}
fibonacciGenerator(1);
fibonacciGenerator(2);
The first code is printing 2 extra Fibonacci number this is because:
you are first pushing 0 and 1 into the array as:
var fArray = [];
fArray.push(0);
if (n >=2 ){
fArray.push(1);
}
and then you loop over again till n times. Because of this reason it prints two extra Fibonacci numbers.
the solution is to either loop over n-2 time or to use the second code.
var fArray = [];
fArray.push(0);
if (n >= 2) {
fArray.push(1);
}
The initial condition is to cover n=1: [0] and n=2: [0,1]
The 2nd code is working because the loop only starts when n is greater than i, so means it skips the loop with n < 2.
For your problem, you don't skip the loop when n < 2.
for (var i = 0; i < n; i++) {
fArray.push(fArray[i] + fArray[i + 1]);
}
You can imagine the result will be like below when n < 2 with your loop.
Note that the inital value is fArray = [0]
fArray.push(fArray[0] + fArray[1]); //fArray[1] is undefined because you only have 1 item in your array
In this case fArray[0] + fArray[1] ==> 0 + undefined = NaN
So that's why your logic does not work when n < 2
To correct it, you need to avoid the loop if n < 2
//if n=1 or n=2, it won't trigger the loop due to `i < n-2`
for (var i = 0; i < n-2; i++) {
fArray.push(fArray[i] + fArray[i + 1]);
}
The idea to have i start with 0 instead of 2, and to adjust the body of the loop accordingly, is fine, but there is one thing that the first version didn't adjust: the stop condition of the loop.
By setting i=0, the first version loops 2 times more than the second version. You should also alter the end condition in the same way: instead of i < n, it should have i < n - 2, so to ensure the number of iterations is the same as in the second version.
Not related to your question, but the console.log should better be placed outside of the function. The job of the function should be to return the array, not to print it. So also, when n > 0 is false, it should return an empty array.
function fibonacciGenerator(n) {
var fArray = [];
if (n > 0) {
fArray.push(0);
if (n >= 2) {
fArray.push(1);
}
for (var i = 0; i < n - 2; i++) {
fArray.push(fArray[i] + fArray[i + 1]);
}
}
return fArray;
}
console.log(fibonacciGenerator(1));
console.log(fibonacciGenerator(2));
First you have to identify the pattern.
Fibonacci series -> 0 1 1 2 3 5 8 13 21
Term -> 0 1 2 3 4 5 6 7 8
0th term =0, 1st term =1
From the second term,
2nd = 1st term + 0th term = 1+0 = 1
3rd = 2nd term + 1st term = 1+1 = 2
4th = 3rd term + 2nd term = 2+1 = 3
5th = 4th term + 3rd term = 3+2 = 5
nth = (n-1) + (n-2)
since the first 2 terms are fixed, you have to start for loop from i= 2.
Also, according to the above shown pattern, you have to use following code inside the for loop.
fArray.push(fArray[i - 1] + fArray[i-2]);

Determining if an array is a factor chain

I would love to know why this code is failing some tests. It is intentionally not using any ES6 code.
Here is the prompt:
*A factor chain is an array where each previous element is a factor of the next consecutive element. The following is a factor chain:
[3, 6, 12, 36]
// 3 is a factor of 6
// 6 is a factor of 12
// 12 is a factor of 36
Create a function that determines whether or not an array is a factor chain.*
My code:
function factorChain(arr) {
var isChain = true;
for (var i = 0; i < arr.length; i++) {
if ((arr[i + 1] / arr[i]) !== Math.floor(arr[i + 1] / arr[i])) {
isChain = false;
}
}
return isChain;
}
You should loop up to arr.length - 1 as you are accessing the element at the current index and the one at the next index on each iteration. Using the remainder operator to check if a number is a factor of another can enhance code clarity. Furthermore, there is no need to assign the result to a variable; simply returning false the first time the condition does not match will exit the function.
function factorChain(arr) {
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i+1] % arr[i] != 0) {
return false;
}
}
return true;
}

Validate the first or last consecutive and equal numbers

I need to validate that the first two digits of a number which are not consecutive or equal.
This is for a ReactJS project, using a conditional "for" and "if" to achieve the validation.
I have this code:
for (let i = 0; i < arrayPassword.length - 1; i++)
{
const actual = parseInt(arrayPassword[i])
const next = parseInt(arrayPassword[i + 1])
//validate consecutive and equal numbers
let isConsecutive = actual + 1 === next || actual === next ? true : false;
if (isConsecutive) {
callback(`consecutive and equal numbers are not allow.`);
} else {
callback();
}
}
At this moment I can validate the full expression when I have a 4 digits consecutive or equal, for example:
(1111, 2222, 3333, 1234, 2345, 6789, ...)
and it's ok, but the problem appears when the first two digits are equal or consecutive, for example:
(1147, 2293, 3360, 1244, 6750, 8952, ...)
I hope that through a condition the numbers like the previous examples do not enter the conditional If.
I appreciate the interest in helping me.
I believe that this simple function do what you need - checks if any two adjacent numbers in a password array are equal or consecutive
function neighboursAreEqual(arrayPassword) {
for (var i = 0; i < arrayPassword.length - 1; i++) {
const current = parseInt(arrayPassword[i]);
const next = parseInt(arrayPassword[i + 1]);
if (current === next || Math.abs(current - next) === 1) return true;
}
return false;
}
// to test how it works
console.log(neighboursAreEqual([])) // false (no symbols to compare)
console.log(neighboursAreEqual(['1'])) // false (no neighboring symbol)
console.log(neighboursAreEqual(['1', '2'])) // true (consecutive)
console.log(neighboursAreEqual(['1', '3'])) // false
console.log(neighboursAreEqual(['2', '2'])) // true(equal)
console.log(neighboursAreEqual(['0', '2', '4'])) // false
console.log(neighboursAreEqual(['0', '2', '3'])) // true (consecutive)
console.log(neighboursAreEqual(['0', '8', '2', '2'])) // true (consecutive)
If you need to compare only first two symbols in array (though I don't know the reason for such requirement) the function becomes even easier - you won't even need for there...
There's no way to know that a number is invalid before looking at all its digits, but your code calls the callback within the loop, after looking at only two. In fact, the callback is called three times, once on each iteration. To fix it, keep track of each validity check in a separate variable, and only call the callback after the loop completes:
let equalSoFar = true;
let consecutiveSoFar = true;
for (let i = 0; i < arrayPassword.length - 1; i++) {
const actual = parseInt(arrayPassword[i])
const next = parseInt(arrayPassword[i + 1])
// validate equal numbers
// "equalSoFar &&" because after a nonequal digit is encountered, equalSoFar MUST be false
equalSoFar = equalSoFar && actual === next;
// validate consecutive numbers
// "consecutiveSoFar &&": same logic
consecutiveSoFar = consecutiveSoFar && actual + 1 === next;
}
if (equalSoFar || consecutiveSoFar) {
callback(`consecutive and equal numbers are not allowed.`);
} else {
callback();
}
You can also break each validity check into its own function and examine the number array with Array.every. A number array has all equal digits if each of its digits is equal to the first one. It has all consecutive digits if each digit is equal to the first one plus its index in the array.
function allSameDigit(array) {
return array.every(digit => digit === array[0]);
}
function allConsecutiveDigits(array) {
return array.every((digit, index) => +digit === +array[0] + index);
}
function isValid(array) {
return !allSameDigit(array) && !allConsecutiveDigits(array);
}
const testValues = [1111, 2222, 3333, 1234, 2345, 6789, 1147, 2293, 3360, 1244, 6750, 8952]
.map(num => num.toString().split(''));
for (let arr of testValues)
console.log(`${arr.join('')}: ${isValid(arr) ? 'valid' : 'invalid'}`);

javascript hackerranks sherlock and array performance issue

Watson gives Sherlock an array A of length N. Then he asks him to
determine if there exists an element in the array such that the sum of
the elements on its left is equal to the sum of the elements on its
right. If there are no elements to the left/right, then the sum is
considered to be zero. Formally, find an i, such that,
Input Format
The first line contains T, the number of test cases. For each test
case, the first line contains N, the number of elements in the array
A. The second line for each test case contains N space-separated
integers, denoting the array A.
Constraints
1<=T<=10
1<=N<=10^5
1<=Ai<=2*10^4
1<=i<=N
Output Format
For each test case print YES if there exists an element in the array,
such that the sum of the elements on its left is equal to the sum of
the elements on its right; otherwise print NO.
Sample Input
2
3
1 2 3
4
1 2 3 3
Sample Output
NO
YES
Explanation
For the first test case, no such index exists. For the second test
case,
therefore index 3 satisfies the given conditions.
I'm having timeout issues on 3 of the test cases
function check(input) {
var result = "NO";
var sum=0;
input.map(function(data){
sum=sum+(+data);
})
sumLeft=0;
sumRight=sum-(+input[0]);
for(var i=1;i<input.length;i++){
sumLeft=sumLeft+(+input[i-1]);
sumRight=sumRight-(+input[i])
if(sumLeft==sumRight)
{
console.log("YES");
return;
}
}
console.log("NO");
}
function processData(input) {
//Enter your code here
var lines = input.split("\r\n");
for (var m = 2; m < lines.length; m = m + 2) {
check(lines[m].split(" "));
}
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function(input) {
_input += input;
});
process.stdin.on("end", function() {
processData(_input);
});
Loop over the array once to find the sum. Declare two variables: sumLeft and sumRight. sumLeft should have an initial value of 0 and sumRight should be totalSum-arr[0].
Iterate over the array again and increment sumLeft by the (n-1) element and decrement sumRight by the nth element. Keep comparing the two variables to check if they equal each other. You cut your time complexity down to O(n)
The below code passed the test on https://www.hackerrank.com/challenges/sherlock-and-array . The tricky part was setting up default responses for when the array length was 1. I will admit that #trincot 's answer was more efficient (n as opposed to 2n) for arrays containing only positive integers.
function check(input) {
var result = "NO";
var sum=0;
if(input.length == 1){
console.log("YES");
return;
}
input.map(function(data){
sum=sum+(+data);
})
sumLeft=0;
sumRight=sum-(+input[0]);
for(var i=1;i<input.length-1;i++){
sumLeft=sumLeft+(+input[i-1]);
sumRight=sumRight-(+input[i])
if(sumLeft==sumRight)
{
console.log("YES");
return;
}else if (sumLeft>sumRight) { ///worked both with and without this optimization
console.log("NO");
return;
}
}
console.log("NO");
}
function processData(input) {
//var lines = input.split("\r\n");
var lines = input.split(/\r|\n/)
for (var m = 2; m < lines.length; m = m + 2) {
check(lines[m].split(" "));
}
}
process.stdin.resume();
process.stdin.setEncoding("ascii");
_input = "";
process.stdin.on("data", function(input) {
_input += input;
});
process.stdin.on("end", function() {
processData(_input);
});
You could go through the array from both ends in inwards direction using two pointers (indices). Keep a balance, starting with 0, as follows:
When the balance is negative move the left pointer one step to the right while increasing the balance with the value you leave behind. When the balance is positive, move the right pointer one step to the left while decreasing the balance with the value you leave behind.
When the two pointers meet each other, check the balance. If it is zero, you have success.
Here is the algorithm in ES6 code, together with a text area where you can adapt the input according to the required input format:
function hasMiddle(a) {
var balance = 0, i = 0, j = a.length-1;
while (i < j) balance += balance > 0 ? -a[j--] : a[i++];
return !balance;
}
// I/O: event handling, parsing input, formatting output
var input = document.querySelector('textarea');
var output = document.querySelector('pre');
input.oninput = function() {
var lines = this.value.trim().split(/[\r\n]+/).filter(s => s.trim().length);
// Strip the case count and array element counts:
lines = lines.slice(1).filter( (s, i) => i % 2 );
// Call function for each test case, returning array of booleans:
var results = lines.map( line => hasMiddle(line.match(/\d+/g).map(Number)) );
// Output results
output.textContent = results.map( pos => pos ? 'YES' : 'NO' ).join('\n');
}
// Evaluate input immediately
input.oninput();
Input:<br>
<textarea style="width:100%; height:120px">2
3
1 2 3
4
1 2 3 3
</textarea>
<pre></pre>
This algorithm requires your input array to consist of non-negative numbers.
If you need to support negative numbers in your array, then the algorithm needs to go through the array first to calculate the sum, and then go through the array again to find the point where the balance reaches 0:
function hasMiddle(a) {
var balance = a.reduce( (sum, v) => sum + v );
return !a.every ( (v, i) => balance -= v + (i ? a[i-1] : 0) );
}
// I/O for snippet
var input = document.querySelector('textarea');
var output = document.querySelector('pre');
input.oninput = function() {
var lines = this.value.trim().split(/[\r\n]+/).filter(s => s.trim().length);
// Strip the case count and array element counts:
lines = lines.slice(1).filter( (s, i) => i % 2 );
// Call function for each test case, returning array of booleans:
var results = lines.map( line => hasMiddle(line.match(/[\d-]+/g).map(Number)));
// Output results
output.textContent = results.map( pos => pos ? 'YES' : 'NO' ).join('\n');
}
// Evaluate input immediately
input.oninput();
Input:<br>
<textarea style="width:100%; height:120px">2
3
1 2 3
4
1 2 3 3
</textarea>
<pre></pre>
Given that we have a proper array one might do as follows
var arr = [...Array(35)].map(_ => ~~(Math.random()*10)+1),
sum = arr.reduce((p,c) => p+c),
half = Math.floor(sum/2),
ix;
console.log(JSON.stringify(arr));
midix = arr.reduce((p,c,i,a) => { (p+=c) < half ? p : !ix && (ix = i);
return i < a.length - 1 ? p : ix;
},0);
console.log("best possible item in the middle # index", midix,": with value:",arr[midix]);
console.log("sums around midix:",
arr.slice(0,midix)
.reduce((p,c) => p+c),
":",
arr.slice(midix+1)
.reduce((p,c) => p+c));
Of course for randomly populated arrays as above, we can not always get a perfect middle index.

Entering dash between numbers in Javascript

I'm trying to insert a dash between even numbers. However, the program returns nothing when run. When I set the initial list to contain a number, it returns that same number indicating the loop isn't adding anything.
function dashEvenNumbers(numbers) {
var list = [];
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] % 2 == 0 && numbers[i + 1] == 0) {
list.push(i, '-');
} else {
list.push(i);
};
};
alert(list);
return list.join('');
};
alert(dashEvenNumbers(123125422));
You could use a regular expression with look ahead.
console.log('123125422'.replace(/([02468](?=[02468]))/g, '$1-'));
Numbers don't have a length property so numbers.length will be undefined.
You probably want to cast to string first, e.g.:
numbers = String(numbers);

Categories