I need to sort an array of numbers, so that it returns its minumum and its maximum. The code I've written so far doesn't seem to do anything at all.
function sort(array) {
arrayNew = [];
maximum = array[0];
minimum = array[0];
for (i = 0; i < array.length; i++) {
if (maximum < array[i]) {
maximum = array[i];
}
}
arrayNew.push(maximum);
for (i = 0; i < array.length; i++) {
if (minimum > array[i]) {
minimum = array[i];
}
}
arrayNew.unshift(minumum);
return arrayNew;
}
var arr1 = [3, 8, 7, 6, 5, -4, 3, 2, 1];
alert(sort(arr1));
In case you didn't know there is a much simpler way to get the min and max values from an array - use Math.min and Math.min with apply:
var min = Math.min.apply(null, arr1);
var max = Math.max.apply(null, arr1);
DEMO
minumum is spelled incorrectly. It should have been minimum
Don't use your variables without declaring them with var keyword. Otherwise they will become global properties.
Also, you can have your minimum check also in the same loop as maximum. So, your code can be shortened like this
function sort(array) {
var maximum = array[0],
minimum = array[0],
i;
for (i = 0; i < array.length; i++) {
if (maximum < array[i]) {
maximum = array[i];
}
if (minimum > array[i]) {
minimum = array[i];
}
}
return [minimum, maximum];
}
Now that we know, we can do it like this, lets try to shorten it more with ternary operator
function sort(array) {
var maximum = array[0],
minimum = array[0],
i;
for (i = 0; i < array.length; i++) {
maximum = maximum < array[i] ? array[i] : maximum;
minimum = minimum > array[i] ? array[i] : minimum;
}
return [minimum, maximum];
}
var arr = [ 3, 8, 7, 6, 5, -4, 31, 2, 21, 20, 1 ].sort(function(a, b) { return a - b }), // [-4, 1, 2, 3, 5, 6, 7, 8, 20, 21, 31]
min = arr[0], // min
max = arr[arr.length-1]; //max
arrayNew.unshift(minumum); is wrong variable minimum
correct one : arrayNew.unshift(minimum);
Related
I don't know what's wrong, my function miniMaxSum isn't summing 1+3+4+5. At the end, the result array turns into this [ 14, 12, 11, 10 ], when it should looks like this [ 14, 13, 12, 11, 10 ]
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex) continue;
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = 0;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
console.log(miniMaxSum([1, 2, 3, 4, 5]));
You're over-complicating your algorithm by trying to check whether you should add the current number to the overall sum or not. Instead, all you need to do is run a loop over your array, to sum up all your elements in your array. This will give you the total sum of all your elements. Then, again, iterate through your array. For each element in your array subtract it from the sum you just calculated and push it into a new array. This will give you the sum if you were to not use the number in the ith position. You can then find the min/max of this using JavaScript's Math.min and Math.max functions.
Here is an example using .reduce() and .map() to calculate the final result:
const miniMaxSum = arr => {
const sum = arr.reduce((s, n) => n+s, 0)
const results = arr.map(n => sum - n);
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
If you prefer standard for loops, here is an implementation of the above in a more imperative style:
const miniMaxSum = arr => {
let sum = 0;
for(let i = 0; i < arr.length; i++) { // sum all elements
sum += arr[i];
}
let results = [];
for(let i = 0; i < arr.length; i++) {
results[i] = sum - arr[i]; // sum minus the current number
}
return [Math.min(...results), Math.max(...results)];
}
const [min, max] = miniMaxSum([1, 2, 3, 4, 5]);
console.log(min, max);
Assuming you're talking about this question.
Whenever you want to restart the loop, you're setting i=0 but observe that you also have increment statement i++ in for loop so, effectively i starts from 1, not 0. You need to set i=-1 so that i=-1+1 = 0 in subsequent iteration. After doing this, you need to handle a corner case. When skipIndex==arr.length-1, check if i == arr.length-1. If yes, do results.push(actualValue); for the last value and then for loop terminates because i < arr.length is false in next iteration.
Code:
function miniMaxSum(arr) {
let results = [];
let actualValue = 0;
let skipIndex = 0;
for (let i = 0; i < arr.length; i++) {
//skip actual index
if (i == skipIndex){
if(i == arr.length - 1)
results.push(actualValue);
continue;
}
actualValue += arr[i];
//restart the loop
if (i == arr.length - 1) {
skipIndex++;
results.push(actualValue);
actualValue = 0;
i = -1;
}
}
console.log(results);
console.log(Math.min(...results), Math.max(...results));
}
miniMaxSum([1, 2, 3, 4, 5]);
Output
[ 14, 13, 12, 11, 10 ]
10 14
I'm trying to write a function that will identify the longest period of variance in an array of numbers. Variance begins when the previous number is higher than the current, and ends when the next number is the same as the current; however, if variance doesn't end, then it is assumed the variance began with the last two numbers.
For example: [10, 5, 3, 11, 8, 9, 9, 2, 10] The longest period of variance in this array is [5, 3, 11, 8, 9], or just 5 (the length). A variance ends when the following number is the same as the current, in this case, 9.
The function I've written works on this case; however, it doesn't when the entire array has variance, such as [10, 5, 10, 5, 10, 5, 10, 5, 10], which returns 8, when it should be 9.
In the case where the previous number is number is always lower, or always higher than the variance would be 2, because it never ended. For example [2, 4, 6, 8] and [8, 6, 4, 2].
I know the issue with the entire array variance can be solved by starting the for loop at 0, but then the other cases become invalid. Any help is greatly appreciated.
Without further ado, here is my code:
function findVariance(numbers) {
if ([0,1].includes(numbers.length)) return numbers.length;
const variance = [[0]];
let greater = numbers[1] > numbers[0];
let lesser = numbers[1] < numbers[0];
for (let i = 1; i < numbers.length; i++) {
let previous = variance.length - 1;
let previousVarianceGroup = variance[previous];
let previousVarianceGroupValue = previousVarianceGroup[previousVarianceGroup.length - 1];
if (greater) {
if (numbers[i] < numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = false;
lesser = true;
} else {
greater = numbers[i] < numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else if (lesser) {
if (numbers[i] > numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = true;
lesser = false;
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] > numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
}
const result = [];
for (let i = 0; i < variance.length; i++) {
result[i] = variance[i].length;
}
result.sort();
return result[result.length - 1];
}
console.log(findVariance([10, 5, 3, 11, 8, 9, 9, 2, 10]));
console.log(findVariance([10, 5, 10, 5, 10, 5, 10, 5, 10]));
console.log(findVariance([2, 4, 6, 8]));
Here's what I got (trying to understand the question as best i could)
function calculateVariance(arr) {
// trivial cases
if (arr.length <= 1) { return arr.length; }
// store the difference between each pair of adjacent numbers
let diffs = [];
for (let i = 1; i < arr.length; i++) {
diffs.push(arr[i] - arr[i - 1]);
}
let max = 0;
// if the difference between two numbers is 0, they're the same.
// the base max variance encountered is 1, otherwise it's 2.
// the boolean zen here is that diffs[0] is falsy when it's 0, and truthy otherwise
let count = diffs[0] ? 2 : 1;
// go through the array of differences,
// and count how many in a row are alternating above/below zero.
for (i = 1; i < diffs.length; i++) {
if ((diffs[i] < 0 !== diffs[i - 1] < 0) && diffs[i] && diffs[i - 1]) {
count++;
} else {
max = Math.max(count, max);
// see above
count = diffs[i] ? 2 : 1;
}
}
// account for the maximum variance happening at the end
return Math.max(count, max);
}
You are overcomplicating things a bit, just increase a counter as long as an element equals the next one, reset on equal:
const counts = [];
let count = 0;
for(let i = 0; i < numbers.length - 1; i++) {
if(numbers[i] === numbers[i + 1]) {
counts.push(count);
count = 0;
} else {
count++;
}
}
counts.push(count);
return counts.sort()[counts.length - 1];
I am looking for an implementation in JavaScript for the following problem.
Consider a sorted array:
[1,2,5,9,10,12,20,21,22,23,24,26,27]
I would like to calculate the length of the maximum range that increased by 1, duplicates are not allowed.
The given example has the following ranges:
1,2
9,10
20,21,22,23,24 // the maximum range
26,27
So the return value for the given example should be 5.
I know how to solve this problem with the obvious solution, but I believe it is possible to solve the problem with more efficient and short algorithm.
A short solution
I don't think this is any more efficient than what pretty much everybody else has suggested, but the code is reasonably short and only loops over the array once, except for the first element. Not sure if it's any help:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
Speeding it up
After looking at the code, I realized that there is a way to speed it up slightly, by not checking the last few elements of the array, based on the previous value of best:
var arr = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27];
var streak = 0, best = 0, bestStart;
for (var i = 1; i < arr.length; i++) {
if(best > arr.length - i + streak) break;
if(arr[i]-arr[i-1] === 1) streak++;
else streak = 0;
if (streak > best) [best, bestStart] = [streak, i - streak];
}
var bestArr = arr.slice(bestStart, bestStart + best + 1);
console.log('Best streak: '+bestArr);
One possible solution would be to iterate the array, keeping the the current range as long as the numbers are successors. If the next number is not a successor of the previous number, close the current range and store its length - by comparing it to the length of the last range.
In this approach, the array is iterated only once and the maximum found length of a range is updated in constant time, yielding an O(n) algorithm where n is the number of elements in the input.
An implementation in C#-like pseudocode could be as follows.
int MaximumLength = minus infinity
int CurrentValue = Input[0];
int CurrentLength = 1;
for(int i = 1; i < Input.Length; i++)
{
if ( CurrentValue + 1 == Input[i] )
{
// same range
CurrentLength = CurrentLength + 1;
}
else
{
// new range
MaximumLength = Math.Max(MaximumLength, CurrentLength);
CurrentLength = 1;
}
CurrentValue = Input[i];
}
// check current length again after loop termination
MaximumLength = Math.Max(MaximumLength, CurrentLength);
It is impossible to obtain better than O(n) because the input cannot be read in less than O(n) time. If that would be possible, it would imply that there are instances for which the result does not depend on every element of the input, which is not the case for the given problem. The algorithm Philipp Maurer has sketched below would also yield an O(n) runtime bound if the maximum range length is 1, i.e. no adjacent numbers in the input are successors.
Something like this should find the maximum length first and not last.
Let max = 0
Let n = array length
While n > 2
Let m = 0
While m <= (array length - n)
Let first = m
Let last = m + n - 1
Let diff = (value of element 'last' in array) - (value of element 'first' in array)
if diff = n - 1 then
max = n
stop
end if
Increase m
end while
Decrease n
end while
Edit (javascript implementation)
var a = [1,2,5,9,10,12,20,21,22,23,24,26,27];
var max = 1;
var n = a.length;
while(n > 2) {
var m = 0;
while(m <= a.length - n)
{
var first = m;
var last = m + n - 1;
var diff = a[last] - a[first];
if (diff == n - 1 && diff > max) {
max = n;
break;
}
m++;
}
n--;
}
console.log(max);
JSFiddle
I think looping and comparing with stored previous maximum length is optimal solution. Maybe like this:
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
console.log(findLongestRange(data))
Here is the version with tests to check how it works with different input.
const data = [1, 2, 5, 9, 10, 12, 20, 21, 22, 23, 24, 26, 27]
function findLongestRange(input) {
let maxLength = 0
let currentLength = 0
for (let i = 0; i < input.length; i++) {
if (i !== input.length) {
if (input[i] === input[i + 1] - 1) {
currentLength++
} else {
if (maxLength <= currentLength && currentLength !== 0) {
maxLength = currentLength + 1
}
currentLength = 0
}
}
}
return maxLength
}
console.clear()
;[
[[1,2,5,6,7,1,2], 3],
[[], 0],
[data, 5],
[[1,2,3], 3],
[[1,3,4,6,8,1], 2],
[[1,3,5], 0],
].forEach((test, index) => {
const result = findLongestRange(test[0])
console.assert(result === test[1], `Fail #${index}: Exp: ${test[1]}, got ${result}`)
})
A Python answer:
l = [1,2,5,9,10,12,20,21,22,23,24,26,27]
current_range = None
current_range_val = 0
max_range = 0
max_range_val = 0
for i, j in zip(l, l[1:]):
if j - i == 1:
current_range_val += 1
if current_range is None:
current_range = (i, j)
current_range = (current_range[0], j)
else:
if current_range_val > max_range_val:
max_range = current_range
max_range_val = current_range_val
current_range_val = 0
current_range = (j, None)
print(max_range)
gives
(20, 24)
My function 'extremeValue' takes 2 parameters, an array and a string "Maximum" or "Minimum", and depending on that string it returns the maximum or minimum value of the array. I used an example array 'values' to pass through the function and while it works out the minimum just fine, the maximum comes out to be the last value of the array. What's wrong with my code?
var values = [4, 3, 6, 12, 1, 3, 7];
function extremeValue(array, maxmin) {
if (maxmin === "Maximum") {
var max = array[0];
for (var i = 1; i < array.length; i++) {
if (array[i] > array[i-1]) {
max = array[i];
}
}
return max;
}
else if (maxmin === "Minimum") {
var min = array[0];
for (var j = 1; j < array.length; j++) {
if (array[j] < array[j-1]) {
min = array[j];
}
}
return min;
}
}
console.log(extremeValue(values, "Maximum"));
console.log(extremeValue(values, "Minimum"));
Change the checking with maximum value.
if (maxmin === "Maximum") {
var max = array[0];
for (var i = 1; i < array.length; i++) {
if (array[i] > max) { //not just before 'array[i-1]'
max = array[i];
}
}
return max;
}
OR
Simply Use
Math.max.apply( Math, values );
to find Maximum from values.and
Math.min.apply( Math, values );
for minimum values.
In each loop you must compare an item with maximum (or minimum) value, not before item:
var values = [4, 3, 6, 12, 1, 3, 7];
function extremeValue(array, maxmin) {
if (maxmin === "Maximum") {
var max = array[0];
for (var i = 1; i < array.length; i++) {
if (array[i] > max) {
max = array[i];
}
}
return max;
}
else if (maxmin === "Minimum") {
var min = array[0];
for (var j = 1; j < array.length; j++) {
if (array[j] < min) {
min = array[j];
}
}
return min;
}
}
console.log(extremeValue(values, "Maximum"));
console.log(extremeValue(values, "Minimum"));
Alternatively you can use the Math function to shorten your code:
var values = [4, 3, 6, 12, 1, 3, 7];
function extremeValue(array, maxmin) {
if (maxmin === "Maximum") {
return Math.max.apply(null, array);
}
else if (maxmin === "Minimum") {
return Math.min.apply(null, array);
}
}
console.log(extremeValue(values, "Maximum"));
console.log(extremeValue(values, "Minimum"));
Is this a good way or the best way to implement Counting Sort in Javascript?
Can't find a standard JS Counting Sort example.
function countingSort(arr){
var helper = []; // This helper will note how many times each number appeared in the arr
// Since JS arrary is an object and elements are not continuously stored, helper's Space Complexity minor that n
for(var i = 0; i<arr.length; i++){
if(!helper[arr[i]]){
helper[arr[i]] = 1;
}else{
helper[arr[i]] += 1;
}
}
var newArr = [];
for(i in helper){
while(helper[i]>0){
newArr.push(parseInt(i));
helper[i]--;
}
}
return newArr;
}
var arr = [5,4,3,2,1,0];
console.log(countingSort(arr)); // [0, 1, 2, 3, 4, 5]
The code is correct, with some comments:
In general, the use of for..in on arrays is discouraged, but unless you define enumerable properties on the Array prototype (which is a bad idea anyway), your use of it is fine to me
You could improve the part where you loop to push the same value several times. This can be done in "one" go by concatenating Array(helper[i]).fill(i) to the results.
You could also use reduce to make the function more functional programming style. In the extreme, it could look like this:
function countingSort(arr){
return arr.reduce( (acc, v) => (acc[v] = (acc[v] || 0) + 1, acc), [] )
.reduce( (acc, n, i) => acc.concat(Array(n).fill(i)), [] );
}
// Sample run:
var arr = [5,4,3,2,1,0];
console.log(countingSort(arr)); // [0, 1, 2, 3, 4, 5]
counting sort is to start by initializing an auxiliary array of length k, that will hold the count of each number. Each index has an initial value of 0. After that, you loop through the input array and increase the “count” for each value by 1 every time you encounter that number in the array. Now, the auxiliary array holds the number of times each element is in the input array. The last step is to loop from the minimum value to the maximum value. In this loop, you’ll loop through each corresponding value in the count array, and add the elements who’s count is greater than 0 to the array in sequential order. You add each item by using a secondary incrementing variable (e.g. if we’re using “i” to loop from the min to max values, then we’ll use “j” to loop through the array), then increasing that second incrementing variable so the next item is placed in the next highest array index, and finally you decrease the value of the current item in the count array so that you don’t add too many of elements that value.
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
const countingSort = (arr, min, max) => {
let counters = [...Array(max+1)].map(e => 0);
let result = []
for(let i = min; i < max; i++){
counters[arr[i]] += 1
}
for(let j = min; j <= max; j++){
while( counters[j] > 0){
result.push(j)
counters[j]--
}
}
return result
}
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
const countingSort = (arr, min, max) => {
const count = {};
// First populate the count object
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]] += 1;
}
/* Now, count is indexed by numbers, with values corresponding to occurrences, eg:
* {
* 3: 1,
* 4: 0,
* 5: 2,
* 6: 1,
* 7: 0,
* 8: 0,
* 9: 1
* }
*/
// Then, iterate over count's properties from min to max:
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
};
console.log(countingSort([3, 6, 5, 5, 9], 3, 9));
let a = [2, 1, 1, 0, 2, 5, 4, 0, 2, 8, 7, 7, 9, 2, 0, 1, 9];
let max = Math.max(...a);
let min = Math.min(...a);
function countingSort(arr) {
const count = [];
for (let i = min; i <= max; i++) {
count[i] = 0;
}
for (let i = 0; i < arr.length; i++) {
count[arr[i]]++;
}
const sortedArr = [];
for (let i = min; i <= max; i++) {
while (count[i] > 0) {
sortedArr.push(i);
count[i]--;
}
}
return sortedArr;
}
console.log(countingSort(a));
The simplest way to solve this problem you write like this:
const range = (start, stop, step) => {
if (typeof stop == "undefined") {
stop = start;
start = 0;
}
if (typeof step == "undefined") step = 1;
if ((step > 0 && start >= stop) || (step < 0 && start <= stop)) return [];
let result = [];
for (let i = start; step > 0 ? i < stop : i > stop; i += step)
result.push(i);
return result;
};
const numbers = [1, 2, 2, 2, 1, 3, 3, 1, 2, 4, 5];
const max = Math.max.apply(Math, numbers);
let count = Array.apply(null, Array(max + 1)).map(() => 0);
for (x of numbers)
count[x] += 1;
let arr = [];
for (x in range(max + 1))
for (i in range(count[x]))
arr.push(parseInt([x]));
console.log(arr);