Leetcode 4sums concise solution - javascript

Recently doing leetcode but encounter difficulties in this 4 sum question. For the kSum function below, I saw some of the solutions online, passing an empty array as a parameter to store the result. I think it makes kSum() too many parameters.
I am thinking of refactoring kSum() holds a parameter of itself but not much process. It return something strange(eg. an empty array)
I would like to ask what I am missing to make my algorithm works? I think the problem may due to the second for loop which loop through kSum(nums, i+1, ...) ?
const fourSum = (nums, target) => {
const sortedNumsArray = nums.sort((a, b) => a - b)
return kSum(sortedNumsArray, 0, 4, target)
}
const kSum = (nums, start, k, target) => {
const result = [];
if( nums.length === start || nums[nums.length - 1] * k < target || nums[start] * k > target) return result;
if (k === 2) {
return twoSum(nums, 0, target)
} else {
let shouldCheck = false;
for (let i = start; i < nums.length; i++) {
if (shouldCheck && nums[i] !== nums[i - 1]) {
for (let set of kSum(nums, i + 1, k - 1, target - nums[i])) {
result.push([nums[i]])
result[result.length - 1].concat(set)
}
}
shouldCheck = true;
}
}
return result;
}
const twoSum = (nums, start, target) => {
let left = start;
let right = nums.length - 1
let subResult = []
while (left < right) {
let sum = nums[left] + nums[right]
if (sum === target) {
subResult.push([nums[left++], nums[right--]])
while (left < right && nums[left] === nums[left + 1]) { left++ }
while (left < right && nums[right] === nums[right - 1]) { right-- }
} else if (sum > target) {
right--
} else {
left++
}
}
return subResult;
}

Related

Two Sum Array - Brute Force - what am I doing wrong?

var twoSum = function(nums, target) {
let index = 0
let i = 1
while (index <= nums.length - 1) {
while (i <= nums.length - 1) {
if (nums[index] + nums[i] === target) {
if (nums[index] === nums[i]) {
i = i + 1
}
return([index, i])
} else {
i = i + 1
}
}
index = index + 1
i = 0
}
};
twoSum([3, 3], 6)
expected output: [0, 1]
received: [0, 2]
description: Given an array of integers nums and an integer target, return indices of the two numbers such that they add up to target.
You need to remove below code when you found the matched result
if (nums[index] === nums[i]) {
i = i + 1
}
var twoSum = function(nums, target) {
let index = 0
let i = 1
while (index <= nums.length - 1) {
while (i <= nums.length - 1) {
if (nums[index] + nums[i] === target) {
return([index, i])
} else {
i = i + 1
}
}
index = index + 1
i = 0
}
};
console.log(twoSum([3, 2, 0,1,4], 6))
Just remove this block.
if (nums[index] === nums[i]) {
i = i + 1
}
BTW, why you write this code from the start. You are not getting all the possible numbers. No matter how long the input array is, you just return 2 indexes.
let index = 0
while (index <= nums.length - 1) {
let i = 0
while (i++ <= nums.length - 1) {
if (index!==i && nums[index] + nums[i] === target) {
return([index, i])
}
}
index++
}
#lucumt already pointed out that you should leave out two lines of your code. However, a slightly more conventional way of expressing your function would involve for() loops as they would make the code slightly more readable than the chosen while() construct. The inner loop should also always start at index+1, see below:
var twoSum = function(nums, target) {
const res=[];
for (let index=0; index <nums.length; index++) {
for (let i=index+1;i <nums.length; i++) {
if (nums[index] + nums[i] === target ) res.push([index, i]);
}
}
return res
}
console.log(twoSum([3, 3], 6)) // [[0,1]]
// second example:
console.log(twoSum([1,6,4,7,3,2,8,3], 6)) // [[2,5],[4,7]]
My snippet will return all possible sums in an array of arrays. If you only want the first solution, simply do twoSum(arr,targetNum)[0].
You can use for-loop with the same logic because it looks more simple.
var twoSum = function(nums, target) {
for(let i=0; i<nums.length; i++){
for(let j=i+1; j<nums.length; j++){
if(nums[i] + nums[j] === target){
return [i, j]
}
}
}
};
let index = 0
let i = 1
while (index <= nums.length - 1) {
while (i <= nums.length - 1) {
if (nums[index] + nums[i] === target) {
// if (nums[index] === nums[i]) {
// i = i + 1
// }
return([index, i])
} else {
i = i + 1
}
}
index = index + 1
i = 0
}
};
console.log(twoSum([3, 3], 6));
Skip that "if" statement above it will increase your i's value for this case.

JS Function works with individual arrays but misbehaves when trying to loop through an array of arrays

I am trying to solve a problem where I am required to loop through an array of arrays, each of which contains a list of numbers that together make up a credit card number. I've been asked to use the Luhn algorithm to validate these numbers, working from the rightmost number in each array to the leftmost. I came up with a function that successfully returns true or false for each array correctly (I know in advance that 5 are valid and 5 are false while a remaining 5 are not known). However, when I then try to loop through the array containing all these arrays, calling the function on them each in turn, the program hangs for ages and finally returns a long list of trues, far longer than the 15 results I expect. My code is below, validateCred seems to work for each card number individually, but findValidCards does not. I can't see why this is happening, can anyone enlighten me?
const validateCred = arr => {
const resultArray = [];
let index = (arr.length) - 1;
if ((index % 2) != 0) {
for (i = index; i >= 0; i--) {
if ((i % 2) == 0) {
let doubled = arr[i] * 2;
if (doubled > 9) {
let numToUnshift = doubled - 9;
resultArray.unshift(numToUnshift);
} else {
resultArray.unshift(doubled);
};
} else {
resultArray.unshift(arr[i]);
};
};
} else {
for (i = index; i >= 0; i--) {
if ((i % 2) != 0) {
let doubled = arr[i] * 2;
if (doubled > 9) {
let numToUnshift = doubled - 9;
resultArray.unshift(numToUnshift);
} else {
resultArray.unshift(doubled);
};
} else {
resultArray.unshift(arr[i]);
};
};
};
const reducer = (acc, curr) => acc + curr;
let sum = resultArray.reduce(reducer);
if ((sum % 10) == 0) {
return true;
} else {
return false;
};
}
const findInvalidCards = array => {
let resultArray = [];
for (i = 0; i < array.length; i++) {
let card = array[i];
let result = validateCred(card);
console.log(result);
};
};

Is this Quick Sort Logic Correct?

I have tried to implement Quick-Sort in Javascript without any reference to psuedo Code. Is this correct implementation? if not how can i improve on it.
const quickSort = (arr = []) => {
const length = arr.length;
if (length === 0 || length === 1) {
return arr;
}
const pivot = arr[0];
const leftArray = [];
const rightArray = [];
for (let i = 1; i < length; i++) {
if (arr[i] < pivot) {
leftArray.push(arr[i]);
} else {
rightArray.push(arr[i]);
}
}
return [...quickSort(leftArray), pivot, ...quickSort(rightArray)];
};
console.log(quickSort([2, 45, 6, 7, 8, 1]));
I have added code of test case and executed it over 250000 times.
// Function to generate random array.
const generateRandomArray = n =>
Array.from({
length: n
}, () => Math.floor(Math.random() * n));
// Function to check whether array is sorted.
const checkSorted = (arr = []) => {
let sorted = true;
for (let i = 1; i < arr.length; i++) {
if (arr[i] < arr[i - 1]) {
sorted = false;
break;
}
}
return sorted;
};
// Testing Quick-Sort
const testQuickSort = () => {
for (let i = 1; true; i++) {
const sortedArray = quickSort(generateRandomArray(Date.now() % 100000));
const isSorted = checkSorted(sortedArray);
if (!isSorted) {
console.log("error");
break;
}
console.log("pass", i);
}
};
testQuickSort();
You can try the following Solution
function pivot(arr, start = 0, end = arr.length - 1) {
const swap = (arr, idx1, idx2) => {
[arr[idx1], arr[idx2]] = [arr[idx2], arr[idx1]];
};
// We are assuming the pivot is always the first element
let pivot = arr[start];
let swapIdx = start;
for (let i = start + 1; i <= end; i++) {
if (pivot > arr[i]) {
swapIdx++;
swap(arr, swapIdx, i);
}
}
// Swap the pivot from the start the swapPoint
swap(arr, start, swapIdx);
return swapIdx;
}
function quickSort(arr, left = 0, right = arr.length -1){
if(left < right){
let pivotIndex = pivot(arr, left, right) //3
//left
quickSort(arr,left,pivotIndex-1);
//right
quickSort(arr,pivotIndex+1,right);
}
return arr;
}
console.log(quickSort([100,-3,2,4,6,9,1,2,5,3,23]));

JavaScript Quicksort recursive

I´m trying to implement a quicksort algorithm for an int array in JavaScript.
I´ve got a problem in my code. The first few ints get sorted well but at the end of the sortet array there is always one integer which is placed many times although its only one time in the array which should be sorted. Hopefully someone will find my fault.
Thanks.
function quicksort(array) {
var randomPlace = Math.round(Math.random() * array.length);
var pivotelement = array[randomPlace];
left = new Array;
right = new Array;
for (var i = 0; i < array.length; i++) {
if (array[i] < pivot) {
left[left.length] = array[i];
} else {
right[right.length] = array[i];
}
}
if ((left.length == 0 || left.length == 1) && (right.length == 0 || right.length == 1)) {
return left.concat(right);
} else if (left.length == 0 || left.length == 1) {
return (left.concat((quicksort(right))));
} else if (right.length == 0 || right.length == 1) {
return ((quicksort(left)).concat(right));
} else {
return (quicksort(left)).concat((quicksort(right)));
}
}
Beside some nameming confusion, like pivotelement vs pivot and Math.round vs Math.floor, you need to tackle the problem of for example [1, 1, 1] which is always returning left = [] and right = [1, 1, 1], that calls quicksort([1, 1, 1]) ad infinitum.
To overcome this problem, you need to check for empty left and with right every element, if it is equal to the random pivot. Then return right, without calling quicksort again.
function quicksort(array) {
var randomPlace = Math.floor(Math.random() * array.length),
pivot = array[randomPlace],
left = [],
right = [],
i;
for (i = 0; i < array.length; i++) {
(array[i] < pivot ? left : right).push(array[i]);
}
console.log(pivot, JSON.stringify(array), JSON.stringify(left), JSON.stringify(right));
// prevent looping forever
if (!left.length && right.every(function (v) { return v === pivot; })) {
return right;
}
if (left.length <= 1 && right.length <= 1) {
return left.concat(right);
}
if (left.length <= 1) {
return left.concat(quicksort(right));
}
if (right.length <= 1) {
return quicksort(left).concat(right);
}
return quicksort(left).concat(quicksort(right));
}
console.log(quicksort([2, 7, 4, 8, 3, 11, 49, 20, 10, 1, 1, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Another solution would be to separate the array into three arrays, one for smaller values, one for equal values and one for greater values. Then sort only the smaller and greater arrays.
function quicksort(array) {
var randomPlace = Math.floor(Math.random() * array.length),
pivotValue = array[randomPlace],
left = [],
pivot = [],
right = [],
i;
for (i = 0; i < array.length; i++) {
if (array[i] === pivotValue) {
pivot.push(array[i]);
continue;
}
(array[i] < pivotValue ? left : right).push(array[i]);
}
console.log(pivotValue, JSON.stringify(array), JSON.stringify(left), JSON.stringify(pivot), JSON.stringify(right));
if (left.length <= 1 && right.length <= 1) {
return left.concat(pivot, right);
}
if (left.length <= 1) {
return left.concat(pivot, quicksort(right));
}
if (right.length <= 1) {
return quicksort(left).concat(pivot, right);
}
return quicksort(left).concat(pivot, quicksort(right));
}
console.log(quicksort([2, 7, 4, 8, 3, 11, 49, 20, 10, 1, 1, 1]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
heres a short version of quick sort written in JS exactly as it is seen in Intro To Algorithms, hope this helps!
var partition = function (arr, low, high) {
var x = arr[high]
var i = low - 1
for (var j = low; j <= high - 1; j++) {
if (arr[j] <= x) {
i++
var temp = arr[i]
arr[i] = arr[j]
arr[j] = temp
}
}
var temp = arr[i + 1]
arr[i + 1] = arr[high]
arr[high] = temp
return i + 1
}
var quickSort = function (arr, low, high) {
if (low < high) {
index = partition(arr,low,high)
if (low < index-1) quickSort(arr,low,index-1)
if (index+1 < high) quickSort(arr,index+1,high)
}
}
var list2 = [1000,13,12,1001,82,1,2,4,3,0]
console.log(quickSort(list2,0,list2.length))
also on my GitHub
I think you are identifying the randomPlace wrongly. It returns undefined some times because you're using Math.round().
Try this instead:
var randomPlace = Math.floor(Math.random() * array.length);
Also, use the following code when initializing left, and right:
var left = new Array();
var right = new Array();
Also, you need to change the pivot in array[i] < pivot to pivotElement.
You can see my complete fiddle here

How to write quick sort on Node.js

I'm continue trying to write a alrorithms on Node.js like on the book Algorithms, 4th ed. Sedgewick, Wayne. There all the examples written on Java.
I have this quick sort module:
"use strict";
const _ = require('lodash');
module.exports = (function () {
function _partition(array, lo, hi) {
let i = lo;
let j = hi + 1;
let v = array[lo];
while (true) {
while (_less(array[++i], v)) {
if (i === hi) {
break;
}
}
while (_less(v, array[--j])) {
if (j === lo) {
break;
}
}
if (i >= j) {
break;
}
_exch(array, i, j);
}
_exch(array, lo, j);
return j;
}
function sort(array) {
_sort(array, 0, array.length - 1);
}
function _sort(array, lo, hi) {
if (hi <= lo) {
return null;
}
let j = _partition(array, lo, hi);
_sort(array, lo, j - 1);
_sort(array, j + 1, hi);
}
function _less(array, i, min) {
return array[i] < array[min];
}
function _exch(array, i, min) {
let temp = array[i];
array[i] = array[min];
array[min] = temp;
}
return {
sort: sort
};
})();
I use mocha and chai for testing with this function:
function isSorted(array) {
for(let i = 1, size = array.length; i < size; i++) {
if (array[i] < array[i-1]) {
return false;
}
}
return true;
}
and quick sort not working.
I need the same implementation as in book, but on js.
You can see original implementation here: quick sort in java
That implementation is ugly.
Sorry, I won't be able to help you answer a course question, but here is the beauty of a functionally recursive version of quicksort. Never, ever, use the above in javascript.
In ES6
A functionally recursive quicksort.
const quicksort = ([head, ...tail]) => head === undefined ? [] :
[...quicksort([...tail.filter(a => a <= head)]), head, ...quicksort([...tail.filter(a => a > head)])];
Usage
console.log(quicksort([1,3,1,0,6,8,9,12,15,22,54, 111,12,2,3,4,5,6,7,-1]));
Your function _less uses indexes as arguments:
function _less(array, i, min) {
return array[i] < array[min];
but you call it with array elements values:
let v = array[lo];
while (_less(array[++i], v)
(and omit first argument array - is it legal in JS?)
Simplest (most readable) quick sort function I've been able to come up with.
Quick Sort (Readability Was The Focus)
let quickSort = (items = [], left = [], right = []) => {
if (items.length <= 1) return items
let pivot = items.pop()
let pushToSide = item => (item < pivot ? left : right).push(item)
items.forEach(pushToSide)
return [...quickSort(left), pivot, ...quickSort(right)]
}
Note: Two other ways to write the same logic above are as follows
for loop instead of foreach
let quickSort = (arr = [], left = [], right = []) => {
if (arr.length <= 1) return arr;
let pivot = arr.pop();
for (let i = 0; i < arr.length; i++)
(arr[i] < pivot ? left : right).push(arr[i]);
return [...quickSort(left), pivot, ...quickSort(right)];
}
_ Quicksort using anonymous callback function within items.forEach instead of variable passed callback_
Anonymous ForEach Callback
let quickSort = (items = [], left = [], right = []) => {
if (items.length <= 1) return items;
let pivot = items.pop();
items.forEach(item => (item < pivot? left : right).push(item))
return [...quickSort(left), pivot, ...quickSort(right)];
}
Short list of other sorts created in js/node.js and references to some useful links
let sort = {
quick: (items = [], left = [], right = []) => {
if (items.length <= 1) return items
let pivot = items.pop()
let pushToSide = item => (item < pivot ? left : right).push(item)
items.forEach(pushToSide)
return [...sort.quick(left), pivot,...sort.quick(right)]
},
bubble: (items = []) => {
for (let passover = 0; passover < items.length; passover++)
{
for (let index = 0; index < items.length; index++)
{
if (items[index] > items[index + 1])
{
let temporary = items[index]
items[index] = items[index + 1]
items[index + 1] = temporary
}
}
}
return items;
},
select: (items = []) => {
for (let passes = 0; passes < items.length; passes++)
{
let min = passes
for (let i = passes; i < items.length; i++)
{
if (items[i] < items[min]) {
min = i
}
}
if (min !== passes) {
let temporary = items[passes]
items[passes] = items[min]
items[min] = temporary
}
}
return items
},
insert: (items = []) => {
for (let i = 1; i < items.length; i++)
{
let index = i-1
let temporary = items[i]
while (index >= 0 && items[index] > temporary)
{
items[index + 1] = items[index]
index--
}
items[index + 1] = temporary
}
return items
},
}
console.log('quick: ', sort.quick([0,43,3,2,3,4]))
console.log("select: ", sort.select([0,43,3,2,3,4]))
console.log("insert: ", sort.insert([0,43,3,2,3,4]))
console.log("bubble: ", sort.bubble([0,43,3,2,3,4]))
<ul>
<li>sort.quick O(n log n) avgerage time complexity</li>
<li>sort.bubble O(n^2) average time complexity</li>
<li>sort.insert O(n^2) average time complexity</li>
<li>sort.select O(n^2) average time complexity</li>
<li>Watch how different sorting algorithms compare in real time</li>
<li>
Time Complexity/Space Complexity cheat sheet</li>
</ul>

Categories

Resources