Hi guys I'm using Codefights concurrently while I learn algorithims & data structures and I cant seem to solve this problem.
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
My code is failing due to performance and I have a general idea why considering my copying of the original array and looping through both. But I am unable to think of a more optimized way.
function almostIncreasingSequence(sequence) {
let result = false;
for(let i = 0; i < sequence.length; i++) {
let newSequence = [...sequence]
newSequence.splice(i,1)
result = isArraySequential(newSequence)
if (result) {
return result;
}
}
return result;
}
function isArraySequential(array) {
let isSequential = true;
for(let i = 0; i < array.length; i++) {
if(i == array.length - 1) {return isSequential}
if (array[i + 1] < array[i] || array[i + 1] == array[i]) {
return !isSequential;
}
}
}
You don't need to constantly check the entire array, nor use multiple loops.
The problem can be broken down to smaller questions. For each element in the list...
Is the current element greater than the last (increasing)?
Yes...
Good! We don't need to do anything.
No...
Has this happened already? If so, it's not almost increasing.
If we remove the previous item, are the surrounding items fixed?
No? What if we remove the current item instead?
Still no? Then that means we can't solve this in one move. It's not almost increasing.
The code would look something like this:
function almostIncreasingSequence(sequence) {
let invalidItemsCount = 0;
for (let i = 1; i < sequence.length; i++) {
if (sequence[i] <= sequence[i-1]) {
invalidItemsCount++;
if (invalidItemsCount > 1) return false;
if (sequence[i] <= sequence[i-2] && sequence[i+1] <= sequence[i-1]) return false;
}
}
return true;
}
var test1 = [0,1,2,3,4,7,6,7,8,9,10];
var test2 = [0,1,2,4,3,4,5,7,6,7,8,9,10];
console.log(almostIncreasingSequence(test1));
console.log(almostIncreasingSequence(test2));
Commented version:
function almostIncreasingSequence(sequence) {
//Keep track of how many replacements we've had to make
let invalidItemsCount = 0;
//Start our loop at 1 so that [i-1] doesn't refer to index "-1"
for (let i = 1; i < sequence.length; i++) {
//If this item is not increasing, we'll need to address it
if (sequence[i] <= sequence[i-1]) {
//Increment our invalidItemsCount
invalidItemsCount++;
//If this is our second invalidItem, then it's not almost increasing.
if (invalidItemsCount > 1) return false;
//If removing the previous element doesn't help, and removing the current item doesn't help,
//then we can't solve this in one move. It's not almost increasing.
if (sequence[i] <= sequence[i-2] && sequence[i+1] <= sequence[i-1]) return false;
}
}
//We've made it through the entire loop without fail. This is almost increasing.
return true;
}
var test1 = [0,1,2,3,4,7,6,7,8,9,10];
var test2 = [0,1,2,4,3,4,5,7,6,7,8,9,10];
console.log(almostIncreasingSequence(test1));
console.log(almostIncreasingSequence(test2));
This is my solution to the problem. I hope someone would find it helpful.
function almostIncreasingSequence(sequence) {
let flag = 0;
for (let i = 0; i < sequence.length; i++) {
if (sequence[i] >= sequence[i+1]){
flag++;
if(i !== 0 && sequence[i] >= sequence[i+2]){
if(sequence[i-1] >= sequence[i+1])
return false;
}
}
}
return flag < 2;
}
Checkout this solution I found, time complexity is O(n).Hope someone finds it helpful
function almostIncreasingSequence(){
let bad=0,i; //initialize the number of bad counts
for(i=1; i<sequence.length; i++){
if(sequence[i]<=sequence[i-1]){
bad++
}
// The descriptions say "removing no more than one element from the array."
// if the number of bad counts is more than one, we can't obtain the desired result so return false
if(bad>1) return false
// if the element on current index is less than or equal the adjacent element -2 steps back
// && next element is less than or equal to the element on previous index return false
if(sequence[i]<=sequence[i-2] && sequence[i+1]<=sequence[i-1])return false
}
return true
}
Here is the link
I came up with this solution in TypeScript, I put here to have some feedback.
It works because the boolean is initially undefined.
function almostIncreasingSequence(sequence: number[]): boolean {
let joker : boolean;
console.log(joker);
for (let index = 1; index < sequence.length; index++) {
const element = sequence[index];
if (sequence[index] <= sequence[index-1]) {
if (!joker) {
joker = true;
} else {
return false;
}
}
}
return true;
}
package main
import "fmt"
func main() {
fmt.Println(almostIncreasingSequence([]int{10, 1, 2, 3, 4, 5}))
fmt.Println(almostIncreasingSequence([]int{1, 2, 3, 2, 3, 6}))
fmt.Println(almostIncreasingSequence([]int{1, 2, 3, 4, 99, 5, 6}))
fmt.Println(almostIncreasingSequence([]int{1, 2, 3, 4, 5, 6, 5}))
fmt.Println(almostIncreasingSequence([]int{1, 5, 3, 4, 5, 6, 5}))
}
func almostIncreasingSequence(sequence []int) bool {
count := 0
for i := 1; i <= len(sequence)-1; i++ {
if sequence[i] <= sequence[i-1] {
count++
if count > 1 {
return false
}
if i <= 1 || i == len(sequence)-1 {
continue
}
if sequence[i] <= sequence[i-2] && sequence[i+1] <= sequence[i-1] {
return false
}
continue
}
}
return true
}
Related
Hello I am trying to refactor my function but it doesn't seem to be working properly. It works fine normally which is the commented code. Am I writing this wrong or is there a fundamental flaw in my code?
function isPrime(num) {
// if (num <= 1){
// return false
// } else {
// for(var i = 2; i < num; i++){
// if(num % i === 0) return false;
// }
// }
num <= 1 ? false : {
for(let i = 2; i < num; i++){
num % 1 === 0 ? false
}}
return true;
}
Thanks
As far as I can tell, no language having the ternary operator allows running a block of statements, which is what you are doing. The ternary operator is a shorthand version of:
let result;
if (<condition>)
result = resultTrue;
else
result = resultFalse;
Unless JavaScript stabs be in the back on this one, for is a statement that doesn't return anything, and therefore cannot be used the way you want.
The best you could do, I guess, would be:
function isPrime(num) {
if (num <= 1) {
return false;
}
for(var i = 2; i < num; i++) {
if(num % i === 0) return false;
}
}
The else part omitted since hitting the line after the if necessarily means that the condition for it was not met.
Technically what you have can be brought to life with an IIFE:
function isPrime(num) {
return num <= 1 ? false :
(n => {
for (let i = 2; i < n; i++) {
if (n % i === 0) return false;
}
return true;
})(num)
}
for (let i = 0; i < 10; i++) {
console.log(i, isPrime(i));
}
Now it works and there is a ternary operator inside.
Even the attempt without return can be done, just you need isPrime made into an arrow function:
let isPrime = num => num <= 1 ? false :
(n => {
for (let i = 2; i < n; i++) {
if (n % i === 0) return false;
}
return true;
})(num);
for (let i = 0; i < 10; i++) {
console.log(i, isPrime(i));
}
Tadaam, the num <= 1 ? false : part is literally there in the first line, without that nasty return.
But realistically this is not how isPrime should be implemented, your very first attempt is the best one so far.
If you want an actual improvement, use the fact that divisors come in pairs. If x is a divisor of num, then num/x is also divisor of num. So if you were looking for all divisors of num, you would find them in pairs as soon as x=num/x=sqrt(num), so it's enough to check numbers between 2 and Math.floor(Math.sqrt(num)), inclusive. As you preferably don't want JS to calculate this number in every iteration (when checking the condition), you could count downwards, so
for (let i = Math.floor(Math.sqrt(num)); i >= 2; i--)
I'm a total beginner and I'm stuck completely on this problem. I'm supposed to use a for loop to traverse an array, pushing odd numbers to the 'odd' array, and evens to the 'even' array.
No numbers are showing up in my arrays when I test the code. I've tried writing it the following two ways:
#1
function pickIt(arr){
var odd=[],even=[];
//coding here
for (i = 0; i < arr.length; i++) {
if (arr[i] % 2 !== 0) {
odd.push();
} else {
even.push();
}
console.log(arr[i]);
}
return [odd,even];
#2
function pickIt(arr){
var odd=[],even=[];
//coding here
for (i = 0; i > 0; i++) {
if (i % 2 !== 0) {
odd.push();
} else {
even.push();
}
}
return [odd,even];
}
I've checked out some of the solutions to the problem and with respect to the code I've got in #2, the most common solution I guess has the for condition written like this:
for (i of arr)
and then in the if else statement it's written:
odd.push(i);
even.push(i);
respectively, but I have no idea how people got there especially concerning the 'for' bit. Can anyone help my brain understand this?
function pickIt(arr){
var odd=[],even=[];
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 !== 0) {
odd.push(arr[i]);
} else {
even.push(arr[i]);
}
}
console.log(odd);
console.log(even);
}
pickIt([10,5,6,3,24,5235,31]);
const odds = [];
const evens = [];
function separateOddEven(arr){
for (let i = 0; i < arr.length; i++){
updateArray(arr[i]);
}
}
function updateArray(number){
if (number % 2) {
odds.push(number);
}
else {
evens.push(number);
}
}
separateOddEven([7, 3, 4, 1, 5]);
I'm trying to solve this exercise. There is a string of numbers and among the given numbers the program finds one that is different in evenness, and returns a position of this number. The element has to be returned by its index (with the number being the actual position the number is in). If its index 0, it has to be returned as 1. I have this so far but it's not passing one test. I'm not too sure why because it feels like it should. Is anyone able to see what the error is? Any help is appreciated!
function iqTest(numbers) {
var num = numbers.split(" ");
var odd = 0;
var even = 0;
var position = 0;
for(var i = 0; i < num.length; i++) {
if(num[i]%2!==0) {
odd++;
if(odd===1) {
position = num.indexOf(num[i]) + 1;
}
}
else if(num[i]%2===0) {
even++;
if(even===1) {
position = num.indexOf(num[i]) + 1;
}
}
}
return position;
}
iqTest("2 4 7 8 10") output 3
iqTest("2 1 2 2") output 2
iqTest("1 2 2") outputs 2 when it should be 1
The simplest way is to collect all even/odd positions in subarrays and check what array has the length 1 at the end:
function iqTest(numbers) {
numbers = numbers.split(' ');
var positions = [[], []];
for (var i = 0; i < numbers.length; i++) {
positions[numbers[i] % 2].push(i + 1);
}
if(positions[0].length === 1) return positions[0][0];
if(positions[1].length === 1) return positions[1][0];
return 0;
}
console.log(iqTest("2 4 7 8 10"))
console.log(iqTest("2 1 2 2"))
console.log(iqTest("1 2 2"))
console.log(iqTest("1 3 2 2"))
Your code is overly complex.
Since the first number determines whether you're looking for an even number or an odd one, calculate it separately. Then, find the first number that doesn't match it.
function iqTest(numbers) {
numbers = numbers.split(" ");
var parity = numbers.shift() % 2;
for( var i=0; i<numbers.length; i++) {
if( numbers[i] % 2 != parity) {
return i+2; // 1-based, but we've also skipped the first
}
}
return 0; // no number broke the pattern
}
That being said, iqTest("1 2 2") should return 2 because the number in position 2 (the first 2 in the string) is indeed the first number that breaks the parity pattern (which 1 has established to be odd)
You have to define which "evenness" is the different one. Use different counters for the two cases, and return -1 if you don't have a single different one. Something like this:
function iqTest(numbers) {
var num = numbers.split(" ");
var odd = 0;
var even = 0;
var positionOdd = 0;
var positionEven = 0;
for(var i = 0; i < num.length; i++) {
if(num[i]%2!==0) {
odd++;
if(odd===1) {
positionOdd = i + 1;
}
}
else if(num[i]%2===0) {
even++;
if(even===1) {
positionEven = i + 1;
}
}
}
if (odd == 1)
return positionOdd;
else if (even == 1)
return positionEven;
else
return -1;
}
Note that, if you have exactly a single even number and a single odd one, the latter will be returned with the method of mine. Adjust the logic as your will starting from my solution.
Since the first number determines whether you're looking for an even number or an odd one, calculate it separately.
Then, find the first number that doesn't match it.
function iqTest(numbers){
// ...
const numArr = numbers.split(' ');
const checkStatus = num => (parseInt(num) % 2) ? 'odd' : 'even';
const findUniqueStatus = array => {
let numEvens = 0;
array.forEach(function(value){
if (checkStatus(value) == 'even') { numEvens++; }
});
return (numEvens === 1) ? 'even' : 'odd'
}
let statuses = numArr.map(checkStatus),
uniqueStatus = findUniqueStatus(numArr);
return statuses.indexOf(uniqueStatus) + 1;
}
}
public static int Test(string numbers)
{
var ints = numbers.Split(' ');
var data = ints.Select(int.Parse).ToList();
var unique = data.GroupBy(n => n % 2).OrderBy(c =>
c.Count()).First().First();
return data.FindIndex(c => c == unique) + 1;
}
This is a program that I have wrote to solve a problem. Check if there exists a sum of elements that equal to the maximum number in the array, return true if so, false otherwise.
var found = "false";
var max;
function ArrayAdditionI(array) {
max = Math.max.apply(null,array);
var p = array.indexOf(max);
array.splice(p,1);
array.sort(function(a, b){return a-b;});
found = findSum(array, 0, 0);
return found;
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
found = "true";
break;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
findSum(array, sum, i+2);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1);
}
return found;
}
ArrayAdditionI(readline());
I had to use global variable, found, to indicate where a sum has been found or not. The return statement always returned undefined.
Also, if I use a return statement in the following if statement, the code does not work properly.
if(i+2 < array.length && sum < max){
return findSum(array, sum, i+2);
}
This is not the optimal solution to the problem, but this is the version I got working.
My question is Why am I getting undefined if I use return statement within the if statement. Also, I tried not using global and use return true if sum === max and at the very end return false, it always returns false or undefined.
-- UPDATE 2: Code with error results --
function ArrayAdditionI(array) {
var max = Math.max.apply(null,array);
//remove max element from array
var p = array.indexOf(max);
array.splice(p,1);
//sort array
array.sort(function(a, b){return a-b;});
//call find sum function
return findSum(array, 0, 0, max);
}
function findSum(array, sum, startIndex){
for(var i = startIndex; i < array.length ; i++){
sum += array[i];
if(sum === max){
return true;
}else if(sum > max){
break;
}
if(i+2 < array.length && sum < max){
**return** findSum(array, sum, i+2, max);
}
}
if(startIndex < array.length && sum !== max){
return findSum(array, 0, startIndex+1, max);
}
return false;
}
// calling the first function
ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The start of the program is this call: ArrayAdditionI([ 7, 2,90, 31, 50 ]);
The return should be true.
Also, ArrayAdditionI([ 1,2,3,4 ]); is true.
However, ArrayAdditionI([ 1,2,3,100 ]); is false.
The return statement between ** **, when removed the code works, otherwise I either get false or undefined. I do not understand this part! Why does removing the return solves the problem, I thought every recursive call must be proceeded with a return statement.
Is the problem maybe due to multiple calls ? Am I using recursion in the improper way?
There are a few mistakes on your code that could lead to the error.
T.J. Crowder already said, use actual booleans instead of a string.
The found variable isn't defined inside your findSum function. That makes JavaScript assume you're setting a global variable.
Add var found = false; as the very first line of your findSum function.
Inside the last if inside your for there are a call to the findSum function but it's not returning it's value nor assigning it to the found variable.
Fix those and update your question with the results.
The following function should give you a true or false answer as to whether or not any combination of values inside an array produces the max figure.
var a = [
1, 1, 1, 1, 1, 1,
1, 1, 1, 9
]
var b = [1,1,1,5]
function MembersHoldMaxSum(arr) {
var i, r = false, index, max = Math.max.apply(null, arr), index;
for (i = 0; i <= arr.length - 1; i++) {
for (index = 0; index <= arr.length - 1; index++) {
var new_arr = [], ct;
for (ct = 0; ct <= arr.length - 1; ct++) {
if (index != ct) { new_arr.push(arr[ct]) }
}
while (new_arr.length != 1) {
var sum = 0, ct2 = 0;
for (ct2 = 0; ct2 <= new_arr.length - 1; ct2++) {
sum += new_arr[ct2];
}
if (sum == max) { return true }
new_arr.pop()
}
}
}
return r
}
var returns_true = MembersHoldMaxSum(a);
var returns_false = MembersHoldMaxSum(b);
I am trying to figure out how to find the first missing number of a sequence of numbers like this (1,2,3,5,6,9,10,15)
I want to put the first missing number, #4, into an variable for later use but don't know how to do so?
I have tried this but this only gives me the last number:
var mynumbers=new Array(1,2,3,6,9,10);
for(var i = 1; i < 32; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: "+mynumbers[i]);
break;
}
}
First of all it gives me the first number after an "hole" in the numbersequence, secondly it continues to alert all numbers comming after an "hole" if I don't insert an break. I only want the first missing number of an numbersequence from 1 - 32. How do i do so?
Hoping for help and thanks in advance ;-)
How about this
var mynumbers = new Array(1,2,3,6,9,10);
var missing;
for(var i=1;i<=32;i++)
{
if(mynumbers[i-1] != i){
missing = i;
alert(missing);
break;
}
}
The O(n) solutions are easy , but this is a common interview question and often we look for O(log n) time solution. Here is the javascript code. It's basically a modified binary search.
function misingNumInSeq(source, min = 0, max = source.length - 1){
if(min >= max){
return min + 1;
}
let pivot = Math.floor((min + max)/2);
// problem is in right side. Only look at right sub array
if(source[pivot] === pivot + 1){
return misingNumInSeq(source, pivot + 1, max);
} else {
return misingNumInSeq(source, min , pivot);
}
}
Output
misingNumInSeq([1,2,3,5,6,9,10,15])
4
By if(mynumbers[i] - mynumbers[i-1] != 1), you mean to say the series will always be incrementing by 1?
var missing = (function (arr) {
var i;
for (i = 0; i < arr.length; ++i) {
if (i + arr[0] !== arr[i]) return i + arr[0];
}
if (i < 32) // if none missing inside array and not yet 32nd
return i + arr[0]; // return next
}([1,2,3,6,9,10])); // 4
alert(missing);
You're going to need the break no matter what. That's what it's there for; to stop the loop from continuing on to the end. And you should use the length of the array instead of hardcoding 32 as the end condition, because your numbers only go up to 32, but there are possibly holes in the list so there will not be 32 elements in the array.
Since you know that each element should be 1 more than the previous element, then the number in the hole is clearly mynumbers[i - 1] + 1.
var mynumbers = new Array(1,2,3,6,9,10);
for(var i = 1; i < mynumbers.length; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: " + (mynumbers[i - 1] + 1));
break;
}
}
EDIT: This only holds true for the missing number not being 1. To catch that, you will need to check if (mynumbers[0] != 1)
Edit:
function findFirstMissing(array) {
for (var i = 0; i < array.length; i++) {
if (i+1 !== array[i]) {
return i+1;
}
}
}
function findFirstMissing(array) {
for (var i = 0; i < array.length; i++) {
if (array[i+1] - array[i] !== 1) {
return array[i] + 1;
}
}
}
If you do it this way then storing it in a variable is easy:
var missing = findFirstMissing(array);
const firstNonConsecutive = arr => arr.find((el, i, arr) => (arr[i] - arr[i-1]) !== 1 && i !== 0)
this solution work for an array of positive numbers.
A solution using array.reduce to find the first positive missing integer.
function solution(A) {
return [...A].sort().reduce((acc, curr, i, arr) => {
if (acc > curr) {
arr.splice(1);
return acc;
}
else if (arr[i + 1] - curr > 1 || arr.length === i + 1) {
arr.splice(1);
return curr + 1;
}
return acc;
}, 1);
}
And here are few test cases:
console.log('solution([1, 3, 6, 4, 1, 2])', solution([1, 3, 6, 4, 1, 2]) === 5)
console.log('solution([1, 3, 2, 8, 4])', solution([1, 3, 2, 8, 4]) === 5)
console.log('solution([1])', solution([1]) === 2)
console.log('solution([-1])', solution([-1]) === 1)
console.log('solution([0])', solution([0]) === 1)
console.log('solution([-1, -4, -5, -6, -190343])', solution([-1, -4, -5, -6, -190343]) === 1)
Sometimes you just want simple if you know it's a small array:
let numbers = [1,2,3,6,9,10]
let m = 0
for (const i of numbers) if (i > ++m) break
console.log(m) // 4
Works if you remove 1 from start of array:
numbers = [2,3,6,9,10]
m = 0
for (const i of numbers) if (i > ++m) break
console.log(m) // 1
If the array can be contiguous, and if so you want the next highest number, then:
numbers = [1,2,3,4,5,6,7,8,9]
m = 0
for (const i of numbers) if (i > ++m) break
if (m == Math.max(...numbers)) m++
console.log(m) // 10
Short and sweet!
//Find the missing number in a series
//output must be 12 in a table of 3 given in below series
let abc = [3, 6, 9, 15, 18, 21, 24];
var def = [],
ghi = [];
for (var i = 1; i <= abc.length; i++) {
if (i !== abc.length) {
var diff = abc[i] - abc[i - 1];
if (def.includes(diff) === false) {
def.push(diff);
} else {
ghi.push(diff);
}
}
}
var finalArr = [];
if (ghi.length > def.length) finalArr = ghi;
else finalArr = def;
var finaldiff = finalArr[0];
var finalVal = abc.find((e, i) => {
if (e !== abc.length) {
var diff = abc[i] - abc[i - 1];
return diff > finaldiff;
}
})
console.log(finalVal - diff);
for(var i = 1; i < mynumbers.length; i++) {
if(mynumbers[i] - mynumbers[i-1] != 1) {
alert("First missing number id: "+mynumbers[i-1]+1);
i = mynumbers.length; // Replace the break
}
}
If you want you can add an initial check : if (mynumbers[0] != 1) { ... }
I think this is the simplest and optimum form of just a 2-step solution.
I think no better solution can be possible for this problem than this one.
This code uses minimum no. of variables, loops, conditionals, built-in functions and all the shitty, sloppy, unnecessary code.
This code can handle array of any length.
var mynumbers = new Array(76,77,78,79,80,81,82,83,84,125);
if(mynumbers.length > 1) {
for(var i=0; i<=mynumbers.length-1; i++) {
if(mynumbers[i+1] - 1 !== mynumbers[i]) {
alert("First Missing Term is : "+parseInt(mynumbers[i]+1));
break;
}
}
}