I did a exercise in Leetcode, the problem is shown below:
Given a sorted array and a target value, return the index if the
target is found. If not, return the index where it would be if it were
inserted in order.
You may assume no duplicates in the array.
Here are few examples.
[1,3,5,6], 5 → 2
[1,3,5,6], 2 → 1
[1,3,5,6], 7 → 4
[1,3,5,6], 0 → 0
This is my first try
var searchInsert = function(nums, target) {
if(nums.length === 0){
return -1;
}
var greaterThanPrev = false;
for(var i = 0; i < nums.length; i++){
if(nums[i] === target){
return i;
}else if(nums[i] < target){
greaterThanPrev = true;
}else{
if(greaterThanPrev){
return i;
}
}
}
if(!greaterThanPrev){
return 0
}else{
return nums.length
}
}
Then I think there is no need to iterate all elements in array if the target is greater than current element, so I add a break in the if clause.
var searchInsert = function(nums, target) {
if(nums.length === 0){
return -1;
}
var greaterThanPrev = false;
for(var i = 0; i < nums.length; i++){
if(nums[i] === target){
return i;
}else if(nums[i] < target){
greaterThanPrev = true;
}else{
if(greaterThanPrev){
return i;
}else{
//add this break to avoid iterate all elements in array
break;
}
}
}
if(!greaterThanPrev){
return 0
}else{
return nums.length
}
};
IMO, second solution should be faster than first one, but according by results, the first one is always like 95ms and the solution with break is always more than 120 ms.
Is there any performance issue with keyword break in javascipt?
Regardless of whether it breaks or returns early, I would consider any for loop iterating through an array of numbers O(n). Big O focuses on worst-case analysis and it would be a best-case scenario if the target were less than, or was the first element in the numbers array. This implementation is more minimalistic but also returns early in the for-loop where possible.
function searchInsert(numbers, target) {
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] == target) {
return i;
} else if (numbers[i] > target) {
return i;
}
}
return numbers.length || -1;
}
Related
I'm trying to understand why my solution to this problem is only partially working.
Problem:
Given a sorted array nums, remove the duplicates in-place such that each element appears only once and returns the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
My Solution:
var removeDuplicates = function(nums) {
if (nums.length === 0) return 0;
for (let i = 1; i <= nums.length; i++){
if(nums[i] === nums[i-1]){
nums.splice(nums[i], 1);
}
}
return nums.length;
};
This is the outcome I'm getting on leetcode but I don't understand why my solution stops working and the '3s' are not removed?
Output screenshot:
When you splice an array while iterating over it, the whole array will change in-place. For example, let's say that indexes 0 and 1 are duplicates (i is 1). Then, if you remove index 1 from the array, what used to be at index 2 will now be at index 1, and what used to be at index 3 will now be at index 2, etc.
So, you need to subtract 1 from i when an element is removed, otherwise the next element will be skipped.
You also have an off-by-one-error - iterate i from 1 to i < nums.length so you don't go past the end of the array.
You also need to pass the index to remove to splice, not the value to remove.
var removeDuplicates = function(nums) {
for (let i = 1; i < nums.length; i++){
if(nums[i] === nums[i-1]){
nums.splice(i, 1);
i--;
}
}
return nums.length;
};
console.log(removeDuplicates([0, 0, 0]));
Simple version. Using functions already created
let array = new Set(nums);
let values = array.values();
return Array.from(values);
This'd also pass just fine on constant memory:
const removeDuplicates = function (nums) {
let count = 0;
nums.forEach(function (num) {
if (num !== nums[count]) {
nums[++count] = num;
}
});
return nums.length && count + 1;
};
function removeDuplicates(nums) {
let i = 0;
while(i < nums.length - 1) {
i += 1 - ((nums[i] === nums[i+1]) && nums.splice(i, 1).length)
}
return nums.length;
}
C# simple solution:
public int RemoveDuplicates(int[] nums) {
if (nums.Length == 0)
return 0;
var i = 0;
var start = 0;
var end = 0;
while (end < nums.Length)
{
if (nums[start] != nums[end])
{
nums[++i] = nums[end];
start = end;
}
end++;
}
return i + 1;
}
This question already has answers here:
Looping through array and removing items, without breaking for loop
(17 answers)
Closed 3 years ago.
Here is the question
Q) take 2 arrays and pass it to a function, then check if the square of the array1 is contained in the array2 (Note: Order doesn't matter, also 2 duplicates in arr1[1,2,2], there should be 2 duplicates in arr2[1,4,4]).
I have this code in which, i am trying to convert the indexOf to a for loop and i have included that code which i tried after this code
function same2(arr1, arr2){
if (arr1.length !== arr2.length){
return false;
}
for (let i = 0; i < arr1.length; i++){
let currentIndex = arr2.indexOf(arr1[i] ** 2);
// if the square of arr1 is contained in any of the index in arr2
if (currentIndex === -1){
return false;
}
console.log(arr2);
arr2.splice(currentIndex, 1);
}
return true;
}
same2([10,2, 3, 5], [100, 4, 25, 9]);
Here is the code with 2 for loop and its giving wrong output for the corresponding input.
function same(arr1, arr2){
if (arr1.length !== arr2.length){
return false;
}
for (let i = 0; i < arr1.length; i++){
for (let j = 0; j < arr2.length; j++){
let currentIndex = arr1[i] ** 2;
console.log(currentIndex);
if (currentIndex === -1){
return false;
}
if (arr2[j] === currentIndex){
arr2.splice(currentIndex, 1);
// console.log(arr2);
}
}
}
return true;
}
same([1, 10,2, 4], [10, 1, 16, 4]);
I know i have problem with the index of the array, but i am not able to break it.
What about this functional approach?
test2 = (i1, i2) => i1.length === i2.length && i1.reduce((a,c) => a && i2.includes(c*c), 1)
console.log(test2([1,2,3],[1,4,9]))
Update 1
Here is a double loop approach, but somehow different from yours as you have several things wrong there. First of all: with splice you are modifying the array for which you have a for loop - that is something you should never do. Secondly, you have recalculated the value you are looking for in the inner loop - that made it absolutelly unusable. You don't need that variable at all, but I have used it to be more straightforward.
Update 2
If you want to have an element in arr2 to count only once, you can introduce the trick to remove that element - without modifying the array with splice.
function same(arr1, arr2){
if (arr1.length !== arr2.length){
return false;
}
for (let i = 0; i < arr1.length; i++){
let lookFor = arr1[i] ** 2;
let found = false;
for (let j = 0; j < arr2.length; j++){
if (arr2[j] === lookFor){
delete arr2[j]
found = true
break;
}
}
if(!found) return false
}
return true;
}
console.log(same([1,2,2],[1,4,4]))
console.log(same([1,2,2],[1,1,4]))
In this function I am trying loop into an array, and then return the following thing: if the year is formed by all different digits, then it's a happy year and should be stored where it belongs, in the happy array. If not, it should go in the notHappy array.
Now the problems:
1) The IF condition I tried returns nothing, []. I am quite sure it's not the right way of doing it.
for (var i = 0; i <= t.length; i++) {
if (i[0] != i[1] && i[0] != i[2] && i[0] != i[3]) {
o.happy.push(i++);
} else {
o.notHappy.push(i++)
}
}
2) I tried the same loop with a simple i%2 === 0 condition and I found out that the loop ignores my arr altogether and returns [0, 2, 4] instead of the actual numbers. It's like it would start looping from 0 itself. How come?
function nextHappyYear(arr){
var o = {
happy: [],
notHappy: []
};
var t = arr.map(e => e.toString().split(""));
for (var i = 0; i <= t.length; i++) {
if (i%2 === 0) {
o.happy.push(i++);
} else { o.notHappy.push(i++)}
}
return console.log(o.happy)
}
nextHappyYear([1021, 1022, 1023, 1024]) // returns [0, 2, 4] instead of [1022, 1024]
Your code has some issues
1-for (var i = 0; i <= t.length; i++)
Arrays indexes start from 0 and ends with length - 1. So your condition i <= t.length makes an error. Change it to i < t.length.
2-if (i%2 === 0)
This is not your question condition. You must get all digits in a year and check equality of them.
3-o.happy.push(i++);
This part have 2 problem. First, you push into happy array the index of that year, not the year. Second, i++ increase i by one and one year will get skipped!
4-if (i[0] != i[1] && i[0] != i[2] && i[0] != i[3])
You check just the first digit with others and you don't check second with third and fourth, third digit with forth also.
Try this
function hasDuplicate(arr) {
arr.sort()
for (var i = 0; i < arr.length - 1; i++) {
if (arr[i + 1] == arr[i]) {
return true;
}
}
return false;
}
function happyYear1(arr) {
var o = {
happy: [],
notHappy: []
};
for (var i = 0; i < arr.length; i++) {
if (!hasDuplicate((arr[i] + '').split(""))) {
o.happy.push(arr[i]);
} else {
o.notHappy.push(arr[i]);
}
}
return o;
}
var output = happyYear1([1021, 1022, 1023, 1024]); // returns [0, 2, 4] instead of [1022, 1024]
console.log(output);
I have an javascript array and I want to delete an element based on the value of the array, this is my array and this is what I have tried without success.
array = []
array.push (["Mozilla","Firefox",1.10])
index = array.indexOf(["Mozilla","Firefox",1.10])
array.splice(index, 1)
But it doesn't work, any idea¿?
You're trying to compare arrays, which are objects and have unique addresses. Your index variable is -1.
Try ['Mozilla','Firefox',1.10] === ['Mozilla','Firefox',1.10] in your console, you'll see that just because two arrays have the same values, it doesn't mean they are the same array.
What you need is a deep-equals style of comparison, that checks each value in the array, to see if two arrays have a likeness.
Take a look at lodash's isEqual function for an idea.
Here's a simple looping function:
function deepIndex(array, comparison) {
var i, j;
main:
for (i = 0; i < array.length; i++) {
if (Array.isArray(array[i])) {
for (j = 0; j < array[i].length; j++) {
if (array[i][j] !== comparison[j]) {
continue main;
}
}
return i;
}
}
}
var arr = [];
arr.push('string', ['Mozilla','Firefox',1.10], 'thing');
var index = deepIndex(arr, ['Mozilla','Firefox',1.10])
console.log(index, arr);
arr.splice(index, 1);
console.log(arr);
Take a look at this:
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
This is function, made by the Creator of JQUery.
Basically you take the Index of one thing and than it is getting removed
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
//Equals Function taken from:
//http://stackoverflow.com/questions/7837456/comparing-two-arrays-in-javascript
Array.prototype.equals = function (array) {
// if the other array is a falsy value, return
if (!array)
return false;
// compare lengths - can save a lot of time
if (this.length != array.length)
return false;
for (var i = 0, l=this.length; i < l; i++) {
// Check if we have nested arrays
if (this[i] instanceof Array && array[i] instanceof Array) {
// recurse into the nested arrays
if (!this[i].equals(array[i]))
return false;
}
else if (this[i] != array[i]) {
// Warning - two different object instances will never be equal: {x:20} != {x:20}
return false;
}
}
return true;
}
array = [];
array.push (["Mozilla","Firefox",1.10]);
array.push (["Microsoft","Spartan",1.0]);
array.push (["Safari","Safari",1.4]);
index = indexOfArr(array,["Mozilla","Firefox",1.10]);
array.remove(index, index);
document.getElementById("length").innerHTML = array.length;
for(var i = 0; i < array.length; i++){
document.getElementById("elems").innerHTML += "<br>"+array[i];
}
function indexOfArr(hay, needle){
for(var i = 0; i < hay.length; i++){
if (hay[i].equals(needle)){
return i;
}
}
return -1;
}
<span id = "length"></span><br>
<span id = "elems">Elements:</span>
You can use the fiter metodh, instead of indexOf.
Within the callback of that method, you can choose different approaches:
Use toString on the arrays and compare the two strings
Test for the length and the content, by iterating over the contained elements
... Continue ...
In any case using === will solve the problem, unless the object contained is exactly the same against which you are trying to match.
By the same, I mean the same. We are non speaking about having the same content, but to be the same instance.
Loop over your array and check the equality:
array = [];
array.push(["Mozilla", "Firefox", 1.10]);
for (var i = 0; i < array.length; i++) {
if (arraysEqual(array[i], ["Mozilla", "Firefox", 1.10])) {
array.splice(i, 1);
}
}
function arraysEqual(a, b) {
if (a === b) return true;
if (a === null || b === null) return false;
if (a.length != b.length) return false;
for (var i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
JSFiddle: http://jsfiddle.net/ghorg12110/r67jts35/
Based on this question : How to check if two arrays are equal with JavaScript?
You can do something like this
array = []
array.push (["Mozilla","Firefox",1.10])
tempArray = array[0];
index = tempArray.indexOf("Mozilla","Firefox",1.10)
array.splice(index, 1)
You can build on this if you put for loop instead of hard coding.
What would be a shorter way to write :
if (array1[0] >= array2[0] && array1[1] >= array2[1] && ...) {
do something;
}
I tried creating a function but I was not able to make it work, I'm still quite new at this.
The most elegant way would be to use .every
The every() method tests whether all elements in the array pass the test implemented by the provided function.
if (array1.every(function(e,i){ return e>=array2[i];})) {
do something;
}
This will return true if all elements of a are greater than all elements of b. It will return as early as possible rather than having to compare all of the elements.
function compare(a, b) {
for (i = 0; i < a.length; i++) {
if (a[i] < b[i]) { return false;}
}
return true
}
var isGreater = true;
for (var i = 0; i < array1.length; i++)
{
if (array1[i] < array2[i])
{
isGreater = false;
break;
}
}
if (isGreater)
{
//do something
}
You loop your first array and replace the numbers by the looping variable (i)