How can I optimize this code? Digit N Powers - javascript

Problem source
https://www.freecodecamp.org/learn/coding-interview-prep/project-euler/problem-30-digit-n-powers
I am curious as to how I can optimize this code. The goal of the code is to find a sum of all numbers whose digits, when raised to the power n, add to the source number.
```
function digitnPowers(n) {
let newArr = [];
let total = 0;
for (let i = 2; i <= Math.pow(9, n) * n; i++) {
let product = 0;
let thisVar = i.toString().split("");
console.log(thisVar);
for (let j = 0; j < thisVar.length; j++){
product += Math.pow(thisVar[j], n);
console.log(product);
}
if (product === i) {
newArr.push(i);
}
}
for (let i = 0; i < newArr.length; i++){
total += newArr[i];
console.log(total);
}
return total;
}
```
All of the code, when run, come out with the correct answers:
```
digitnPowers(2); = 0
digitnPowers(3); = 1301
digitnPowers(4); = 19316
digitnPowers(5); = 443839
```
The console logs are only present to help me learn to solve this problem. My first step in optimization would be to remove those.
My concern is that when I run this function with 5, the code needs to loop nearly 300,000 times, and this function with 4, nearly 27,000. If n were 6, it'd require 3.1million loops. As of now, the code works, but slowly. Any ideas?

Related

My browser lags when I try a loop function?

I wrote a simple nested loop function to multiply all items in an array and output the total value, but each time is I run a loop function my browser either crashes or doesn't stop loading
function multiplyAll(arr){
Let product = 1;
for(let i = 0; i <
arr.length; i++){
for(let j = 0; j <
arr[i].length; j *= product);
}
return product;
}
multiplyAll([[1], [2], [3]]);
You are creating an infinite loop here because of
for (let j = 0; j < arr[i].length; j *= product);
Here, j is always 0.
If you want to multiply all the nested value then you should do as:
function multiplyAll(arr) {
let product = 1;
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; ++j)
product *= arr[i][j];
}
return product;
}
console.log(multiplyAll([[1], [2], [3]]));
If you just want to multiple all the nested value then you can simply do as:
function multiplyAll(arr) {
return arr.flat().reduce((acc, curr) => acc * curr, 1);
// If you want to get numbers at any depth then you can flat at any level
// using Infinity as
// return arr.flat(Infinity).reduce((acc, curr) => acc * curr, 1);
}
console.log(multiplyAll([[1], [2], [3]]));
Well, it looks like you have multiple issues, two of them are already as following:
In line 2 you wrote once Let with a big letter at the beginning.
Your second array needs an {} otherwise it will error out
Can you please explain to me j*= product? Can you maybe include a few examples of how you would call this Code and what kind of response you would get? depending on that I will create you a Clear answer!

Find a subset of an array satisfying some condition

Suppose that an array of N numbers is given.
How to find a subset that its sum is multiple of N?
I want to know the best approach.
The recursive function would be the right choice, but stack overflow for large number N isn't allowed.
Here is my code, but it doesn't work.
const arr = [];
const TOTAL_NUM = 5;
let sum = 0;
for (let i = 0; i < TOTAL_NUM; i++) {
arr.push(parseInt(Math.random() * TOTAL_NUM) + 1);
sum += arr[i];
}
const mod = sum % TOTAL_NUM;
for (let i = 0; i < TOTAL_NUM; i++) {
let sum = arr[i]
let found = false;
for (let j = i + 1; j < TOTAL_NUM; j++) {
sum += arr[j];
if (sum % TOTAL_NUM === 0 || (sum - mod) % TOTAL_NUM === 0) {
found = true;
console.log('Sum = %d', sum);
break;
}
}
if (found) break;
}
We don't necessarily need to recurse. We can iterate on the known remainders so far.
JavaScript code below (this is exhaustive; we could have a more space efficient version to return just one subset by adjusting what we store):
// 'rem' stands for "remainder"
function f(A){
let N = A.length
let rems = {0: [[]]}
for (let a of A){
let newRems = {}
for (let rem in rems){
let newRem = (a + Number(rem)) % N
newRems[newRem] = (rems[newRem] || []).concat(
rems[rem].map(x => x.concat(a)))
}
newRems[a % N] = (rems[a % N] || []).concat([[a]])
rems = Object.assign(rems, newRems)
}
return rems[0].slice(1)
}
var A = [1, 6, 2, 3, 4]
console.log(JSON.stringify(A))
console.log(`N: ${A.length}`)
console.log(JSON.stringify(f(A)))
I want to answer my question and to be evaluated by audiences.
This is my current code. I'll explain.
Assume we have an array of N numbers.
In loop for variable i = 0, we get N subsets and its inner sums. If there is at least one subset that its sum is multiple of N, it will be a solution. If not, the value of (sum % N) would take one value between 1 and (N-1). There exist N sums and (N-1) possible remainders. Therefore, there exist at least one pair (n, m) that n-th sum and m-th sum would have the same remainder, where 0 < n < m < N.
In this case, the sum of a subset [arr[n+1], arr[n+2], ... arr[m]] would be the multiple of N. So we can find n and m to solve this problem.
Below is the code to find n and m.
const arr = [];
const TOTAL_NUM = 5;
for (let i = 0; i < TOTAL_NUM; i++) {
arr.push(parseInt(Math.random() * TOTAL_NUM * 10) + 1);
}
console.log(arr.join(', '));
// find n and m
for (let i = 0; i < TOTAL_NUM; i++) {
let sum = 0;
found = false;
for (let j = i; j < TOTAL_NUM; j++) {
sum += arr[j];
if (sum % TOTAL_NUM === 0) {
found = true;
// output result
console.log('Sum = %d, n = %d, m = %d', sum, i, j);
break;
}
}
if (found) break;
}
As you can see, this code requires N * (N-1) / 2 loop, and no memory. Even for very large N, it would take a few milliseconds to find n and m.
It took about 20~80ms to find a solution for N = 10000000 on my computer(Core i5 4460 # 2.90GHz).

How to code all for all cases of Two Sum javascript problem

I have been working on the two sum problem for the past few hours and can't seem to account for the case where there are only two numbers and their sum is the same as the first number doubled.
The result should be [0,1], but i'm getting [0,0].
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return [nums.indexOf(nums[i]), nums.indexOf(nums[b])];
}
}
}
}
console.log(twoSum(nums, targetNum))
Two Sum
My approach uses a javascript object and completes the algorithm in O(n) time complexity.
const twoSum = (nums, target) => {
let hash = {}
for(i=0;i<nums.length;i++) {
if (hash[nums[i]]!==undefined) {
return [hash[nums[i]], i];
}
hash[target-nums[i]] = i;
}
};
console.log(twoSum([2,7,11,15], 9)); // example
This is not the way to solve the problem. Step through the array and save the complement of the target wrt the number in the array. This will also solve your corner case.
You should consider, indexOf(i) -> start from the first element, returns the index when match found! That is why in your code, nums.indexOf(nums[i]) and nums.indexOf(nums[b]) which is basically 3 in all two cases, it will return 0, cause 3 is the first element in array.
instead of doing this, return the index itself.
let nums = [3,3];
let targetNum = 6;
function twoSum(nums, target) {
for (let i = 0; i < nums.length; i++) {
for (let b = i+1; b < nums.length; b++) {
if ((nums[i] + nums[b]) == target) {
return i + "" +b;
}
}
}
}
console.log(twoSum(nums, targetNum))

Simple Feedforward Neural Network in JavaScript

I'm new to this site, so I apologize in advance if I'm doing anything wrong in this post.
I'm currently trying out machine learning, and I'm learning neural networks. I'm currently using http://neuralnetworksanddeeplearning.com/. However, I don't fully understand everything, and all of the code is written in Python (I'm more comfortable with JavaScript).
I've created a program that works for simple data. However, for more complicated data (handwritten digits recognition with MNIST data), the accuracy rate isn't nearly as high as the website above says it will be, by using a neural network of 784 input neurons, 10-400 hidden neurons in the hidden layer (only one hidden layer and tried several possible number of neurons), and 10 output neurons with hundreds of iterations. I think that there is an error with my back propagation step (i.e. the train step, I'm including the other functions here as reference) that prevents it from learning fast enough (BTW, I'm using the cross-entropy as my cost function). I would really appreciate if anyone can help me find the error. Thanks in advance.
Below is the code. The weights are arranged in an array of arrays of arrays (weight[i][j][k] is the weight between the jth neurons in the ith layer and the kth neuron in the (i+1)th layer). Similarly, bias[i][j] is the bias of the (i+1)th layer for the jth neuron. The training data is formatted as an array of objects with keys of inputs and outputs (see example below).
class NeuralNetwork {
constructor(layers) {
// Check if layers is a valid argument
// Initialize neural network
if (!Array.isArray(layers) || layers.length < 2) {
throw Error("Layers must be specified as an array of length at least 2");
}
this.weights = [];
this.biases = [];
for (let i = 0, l = layers.length; i < l; ++i) {
let currentLayer = layers[i];
if (typeof currentLayer === "number" && Number.isInteger(currentLayer) && currentLayer > 0) {
let numWeights = layers[i + 1];
if (i < l - 1) {
this.weights.push([]);
}
if (i) {
this.biases.push([]);
}
// Seed weights and biases
for (let j = 0; j < currentLayer; ++j) {
if (i < l - 1) {
let weights = [];
for (let k = 0; k < numWeights; ++k) {
weights.push(Math.random() * 2 - 1);
}
this.weights[i].push(weights);
}
if (i) {
this.biases[i - 1].push(Math.random() * 2 - 1);
}
}
} else {
throw Error("Array used to specify NeuralNetwork layers must consist solely of positive integers");
}
}
this.activation = (x) => 1 / (1 + Math.exp(-x));
this.activationDerivative = (x) => this.activation(x) * (1 - this.activation(x));
Object.freeze(this);
console.log("Successfully initialized NeuralNetwork");
return this;
}
run(input, training) {
// Forward propagation
let currentInput;
if (training) {
currentInput = [input.map((a) => {return {before: a, after: a}})];
} else {
currentInput = [...input];
}
for (let i = 0, l = this.weights.length; i < l; ++i) {
let newInput = [];
for (let j = 0, m = this.weights[i][0].length, n = (training ? currentInput[i] : currentInput).length; j < m; ++j) {
let sum = this.biases[i][j];
for (let k = 0; k < n; ++k) {
sum += (training ? currentInput[i][k].after : currentInput[k]) * this.weights[i][k][j];
}
if (training) {
newInput.push({
before: sum,
after: this.activation(sum)
});
} else {
newInput.push(this.activation(sum));
}
}
if (training) {
currentInput.push(newInput);
} else {
currentInput = newInput;
}
}
return currentInput;
}
train(data, learningRate = 0.1, batch = 50, iterations = 10000) {
// Backward propagation
console.log("Initialized training");
let length = data.length,
totalCost = 0,
learningRateFunction = typeof learningRate === "function",
batchCount = 0,
weightChanges = [],
biasChanges = [];
for (let i = 0; i < iterations; ++i) {
let rate = learningRateFunction ? learningRate(i, totalCost) : learningRate;
totalCost = 0;
for (let j = 0, l = length; j < l; ++j) {
let currentData = data[j],
result = this.run(currentData.input, true),
outputLayer = result[result.length - 1],
outputLayerError = [],
errors = [];
for (let k = 0, m = outputLayer.length; k < m; ++k) {
let currentOutputNeuron = outputLayer[k];
outputLayerError.push(currentOutputNeuron.after - currentData.output[k]);
totalCost -= Math.log(currentOutputNeuron.after) * currentData.output[k] + Math.log(1 - currentOutputNeuron.after) * (1 - currentData.output[k]);
}
errors.push(outputLayerError);
for (let k = result.length - 1; k > 1; --k) {
let previousErrors = errors[0],
newErrors = [],
currentLayerWeights = this.weights[k - 1],
previousResult = result[k - 1];
for (let i = 0, n = currentLayerWeights.length; i < n; ++i) {
let sum = 0,
currentNeuronWeights = currentLayerWeights[i];
for (let j = 0, o = currentNeuronWeights.length; j < o; ++j) {
sum += currentNeuronWeights[j] * previousErrors[j];
}
newErrors.push(sum * this.activationDerivative(previousResult[i].before));
}
errors.unshift(newErrors);
}
for (let k = 0, n = this.biases.length; k < n; ++k) {
if (!weightChanges[k]) weightChanges[k] = [];
if (!biasChanges[k]) biasChanges[k] = [];
let currentLayerWeights = this.weights[k],
currentLayerBiases = this.biases[k],
currentLayerErrors = errors[k],
currentLayerResults = result[k],
currentLayerWeightChanges = weightChanges[k],
currentLayerBiasChanges = biasChanges[k];
for (let i = 0, o = currentLayerBiases.length; i < o; ++i) {
let change = rate * currentLayerErrors[i];
for (let j = 0, p = currentLayerWeights.length; j < p; ++j) {
if (!currentLayerWeightChanges[j]) currentLayerWeightChanges[j] = [];
currentLayerWeightChanges[j][i] = (currentLayerWeightChanges[j][i] || 0) - change * currentLayerResults[j].after;
}
currentLayerBiasChanges[i] = (currentLayerBiasChanges[i] || 0) - change;
}
}
++batchCount;
if (batchCount % batch === 0 || i === iterations - 1 && j === l - 1) {
for (let k = 0, n = this.weights.length; k < n; ++k) {
let currentLayerWeights = this.weights[k],
currentLayerBiases = this.biases[k],
currentLayerWeightChanges = weightChanges[k],
currentLayerBiasChanges = biasChanges[k];
for (let i = 0, o = currentLayerWeights.length; i < o; ++i) {
let currentNeuronWeights = currentLayerWeights[i],
currentNeuronWeightChanges = currentLayerWeightChanges[i];
for (let j = 0, p = currentNeuronWeights.length; j < p; ++j) {
currentNeuronWeights[j] += currentNeuronWeightChanges[j] / batch;
}
currentLayerBiases[i] += currentLayerBiasChanges[i] / batch;
}
}
weightChanges = [];
biasChanges = [];
}
}
totalCost /= length;
}
console.log(`Training ended due to iterations reached\nIterations: ${iterations} times\nTime spent: ${(new Date).getTime() - startTime} ms`);
return this;
}
}
Example
Tests if a point is inside a circle. For this example, the neural network performs well. However, for more complicated examples such as handwriting recognition, the neural network performs really badly (best I can get for a single neural network is 70% accuracy, compared to the 96% accuracy stated in the website even when using similar parameters).
let trainingData = [];
for (let i = 0; i < 1000; ++i) {
let [x, y] = [Math.random(), Math.random()];
trainingData.push({input: [x, y], output: [Number(Math.hypot(x,y) < 1)]});
}
let brain = new NeuralNetwork([2, 5, 5, 1]);
brain.train(trainingData.slice(0,700), 0.1, 10, 500); // Accuracy rate 95.33% on the remaining 300 entries in trainingData
Ok, I guess I'm going to answer my own question. So, I don't think there is an error in my code and it's perfectly fine to use (albeit really, really inefficient) if anyone wants to.
The reason why my runs on the MNIST data did not give accurate answers come from the fact that I did not process the data at first. The raw data gave the darkness of the 28*28 pixels in the range of [0, 255], which I used directly as the input for each of the training data. The correct procedure here would be to convert this into the range of [0, 1] or [-1, 1].
The reason that the [0, 255] range does not work as well is due to the fact that the second hidden layer of neurons will receive really positive or negative inputs.
When the backpropagation algorithm computes the gradient, the change computed for each weight will be really small as it is proportional to the slope of the activation function at the input to the neuron (the derivative of the logistic function is exp(-x)/(1+exp(-x)), which is close to 0 for really positive and negative values of x). Thus, the neural network will take really long to train and, in my case, was not able to learn the data well.
With the correct method, I am able to achieve around 90% accuracy for a 784*200*10 neural network in a fairly short time, though it still is not nearly as accurate as what the author says he is able to achieve using an even simpler algorinthm in the link mentioned in the question.

Program to generate primes not working

I made the following code to generate an array of primes till a number 'num'.
But It is giving totally unexpected results.
I tried debugging it on chrome but the debugger does not help much as it just skips over the 4th line.
function Sieve(num) {
var arr = Array.from({length:num-1}).map((x,i)=> i+2);
var numb = Math.floor(Math.sqrt(num));
var arra = Array.from({length:numb-1}).map((x,i)=> i+2);
arra.forEach(x => arr = arr.filter(y => ((y%x)!==0)||(y=!x)));
console.log(arr);
}
Sieve(10)
Is this supposed to be Sieve of Eratosthenes algorithm? Just to mention, you know this is not the fastest way to generate primes?
Bersteins's primegen is confirmed faster, and they might be even faster solutions.
That aside, let's display simple code for what you are trying to achieve:
var eratosthenes = function(n) {
// Eratosthenes algorithm to find all primes under n
var array = [], upperLimit = Math.sqrt(n), output = [];
// Make an array from 2 to (n - 1)
for (var i = 0; i < n; i++) {
array.push(true);
}
// Remove multiples of primes starting from 2, 3, 5,...
for (var i = 2; i <= upperLimit; i++) {
if (array[i]) {
for (var j = i * i; j < n; j += i) {
array[j] = false;
}
}
}
// All array[i] set to true are primes
for (var i = 2; i < n; i++) {
if(array[i]) {
output.push(i);
}
}
return output;
};
This is far simpler to understand and split in sections.
BTW, you know Array.from(new Array(n-1), (x,i) => i+2); works? There is no need to array.from() and then .map(), you can pass map function directly into from as a parameter. Also with new Array(n) code is a bit more readable.
This is solution using your principles.
function Sieve(num) {
var arra = Array.from(new Array(num-1), (x,i) => i+2);
var comb = Array.from(new Array(Math.sqrt(num)-1), (x,i) => 2+i);
comb.forEach(x => arra=arra.filter(y => (y%x !== 0) || (y===x) ));
console.log(arra);
}
Sieve(100);
It's on CodePen since JSFiddle breaks. labda solution to Erathostene's sieve

Categories

Resources