Related
Here is one question from hackerrank, I have a solution but there is some testcase failed because time limit exceeded. I don't know the better solution for it.
Find Sum of elements in a subarray (if in subarray has 0, sum = sum + number x)
input:
numbers: main array(1-indexed)
queries:
array of query: left index, right index, number x(0-indexed)
output:
array of sum corresponding with queries.
my solution on C++ code:
vector<long> findSum(vector<int>numbers, vector<vector<int>> queries)
{
vector<long>result;
long sum = 0;
int count = 0;
for(auto i : queries)
{
sum = 0;
count = 0;
int l = i[0] - 1;
int r = i[1]-1;
int x = i[2];
for(int j =l; j<r;j++)
{
sum+=numbers[j]==0?x:numbers[j];
}
result.push_back(sum);
}
return result;
}
As suggested by #Annity, you need to maintain two arrays:
Sum of all numbers so far. At any point of the index, it should have the sum of all previous numbers.
Same as above but it should have the total count of all previous Zeros.
You should avoid nested loops to reduce time complexity. Here is a solution in javascript:
function findSum(numbers, queries) {
let result = [];
let subArraySum = [];
let countZero = numbers[0] == 0 ? 1 : 0;
let zeroArr = [];
zeroArr[0] = countZero;
subArraySum[0] = numbers[0];
for (let i = 1; i <= numbers.length - 1; i++) {
if (numbers[i] == 0) {
countZero++;
zeroArr[i] = countZero;
}
else {
zeroArr[i] = countZero;
}
subArraySum[i] = subArraySum[i - 1] + numbers[i];
}
for (let q of queries) {
if (q.length == 3) {
let i = q[0];
let j = q[1];
let x = q[2];
let sum = 0;
sum = subArraySum[j - 1] - ((i - 2 < 0 ) ? 0 : subArraySum[i - 2]);
sum = sum + (zeroArr[j - 1] - ((i - 2 < 0 ) ? 0 : zeroArr[i - 2])) * x;
result.push(sum);
}
}
return result;
}
console.log(findSum([5, 10, 15], [
[1, 2, 5]
]))
console.log(findSum([0, 10, 15], [
[1, 2, 5]
]))
Here's the solution that occurred to me.
You need to create two new arrays - one for the sums and one for the number of zeroes. Eg. sums[] and zeroes[].
In these two arrays you will store the value for the sum and the number of zeroes from the first element to the current. This is how it goes:
Loop through all of the numbers.
For each number with index i save in sums[i] the cumulative sum of all the elements from the first to the current and in zeroes[i] - the number of zeroes from the first element to the current.
Then loop through all of the queries.
For every query calculate the sum:
You take the sum from the sums array for the element with the right index and deduct the sum for the element before the left index.
(sum = sums[r] - sums[l-1])
If you deduct the count of zeroes in the element before the left index from the number in the element on the right index - you will get the number of zeroes in the interval.
(zero = zeroes[r] - zeroes[l-1])
Then multiply it by the third element in the query and add it to the sum.
And this is how you have the sum for the query.
this is in python
tempRes=0
temp = []
for b in range(len(queries)):
for k in range(queries[b][0]-1,queries[b][1]):
if numbers[k] == 0:
tempRes = tempRes + queries[b][2]
tempRes = tempRes + numbers[k]
temp.append(tempRes)
tempRes = 0
return temp
Your code takes a linear time per query. Invest in a linear time once to precompute an array of partial sums. Then each query will be answered in a constant time.
public static List<Long> findSum(List<Integer> numbers, List<List<Integer>> queries) {
// Write your code here
ArrayList<Long> arr = new ArrayList<>();
for(int i = 0; i < queries.size(); i++) {
int sum = 0;
for(int j = queries.get(i).get(0) - 1; j <= queries.get(i).get(1) - 1; j++) {
if(numbers.get(j) == 0){
sum += queries.get(i).get(2);
} else {
sum += numbers.get(j);
}
}
arr.add((long)sum);
sum = 0;
}
return arr;
}
The logic tries to sum each index with the last index.
But initializes the first index with 0.
The same with counting the zero.
After that, just subtract the left side with the desired index.
Also with the zero value in the index, but multiplid by the queries.
There you have it. I can't post the answer.
JS Solution:
There are two methods to solve this problem (Brute force Solution [Nested Loop]) and that's the method that responds with a timeout error throughout the execution of the test, you need to solve it with another time complexity, here is my answer 1st method O(N^2) and then 2nd method Optimized to be O(N) to solving the timeout error.
Answers in JavaScript wish it helps you.
/*
-- Brainstorming --
Have 1-indexed Array [numbers] of length n;
Have numbers of queries (q). [2D Array]
Each Query => [startIdx i, endIdx r, number x]
Find => Sum of numbers between indexes i and r (both included)
if zero occured in range add x instead of it.
*/
// 1st Method: Brute force Solution [Nested Loop]
function findSum(numbers, queries) {
const sum = new Array(queries.length).fill(0);
for (let i = 0; i < queries.length; i++) {
// let j = queries[i][0] - 1 Cause numbers 1-index not 0
for (let j = queries[i][0] - 1; j < queries[i][1]; j++) {
if (numbers[j] === 0) {
sum[i] += queries[i][2];
} else {
sum[i] += numbers[j];
}
}
}
return sum;
}
// 2nd Method: The Optimized Solution Single Loop
function findSum(numbers, queries) {
const sums = [];
const subArraySum = [];
const zerosArr = [];
let zerosCount = 0;
for (let i = 0; i < numbers.length; i++) {
if (numbers[i] === 0) {
zerosCount++;
zerosArr[i] = zerosCount;
} else {
zerosArr[i] = zerosCount;
}
subArraySum[i] = numbers[i] + (subArraySum[i - 1] || 0);
}
for (let q of queries) {
const i = q[0] - 1;
const r = q[1] - 1;
const x = q[2];
let finalSum = subArraySum[r] - (subArraySum[i - 1] || 0) + (zerosArr[r] - (zerosArr[i - 1] || 0)) * x;
sums.push(finalSum);
}
return sums;
}
console.log("1st Test: " + findSum([5,10,10], [[1,2,5]])) // 15
console.log("2nd Test: " + findSum([-5,0], [ [2, 2 ,20] , [1,2,10]])) // 20 , 5
console.log("3rd Test: " + findSum([-1,-1,1,-4,3,-3,-4], [ [1, 4 ,2]])) // -5
console.log("4th Test: " + findSum([1000000000], [[1, 1,100]]))// 1000000000
console.log("5th Test: " + findSum([-1000000000], [[1, 1,100]]))// -1000000000
Try this(in javascript):
function findSum(numbers, queries) {
// Write your code here
let sumArr = [];
for (let i = 0; i < queries.length; i++) {
let sum = 0;
let start = queries[i][0];
let end = queries[i][1] + 1;
let x = queries[i][2];
const newArr = numbers.slice(start, end);
newArr.forEach((item) => {
if (item === 0) {
sum = sum + x;
}
sum = sum + item;
});
sumArr.push(sum);
}
return sumArr;
}
#!/usr/bin/python3
def solution(numbers, queries):
if not isinstance(numbers, list) and not isinstance(queries, list):
return
result = []
total = 0
for query in queries:
if len(query) == 3:
start = query[0]
end = query[1]
additional = query[2]
selection = numbers[start-1:end]
has_zeros = False
for el in selection:
if el == 0:
has_zeros = True
print(f"has_zeros: {has_zeros}")
print(f"selection: {selection}")
total = sum(selection)
if has_zeros:
total += additional
result.append(total)
return result
if "__main__" == __name__:
# 15
_input = [5, 10, 10]
_queries = [[1], [3], [1, 2, 5]]
print(f"input: {_input}")
print(f"queries: {_queries}")
_output = solution(_input, _queries)
print(f"ouput: {_output}")
Solution in python3 :
def findSum(numbers, queries):
a = [0]
b = [0]
for x in numbers:
a.append(a[-1] + x)
b.append(b[-1] + (x == 0)) if in subarray has 0, sum = sum + number x)
return [a[r] - a[l - 1] + x * (b[r] - b[l - 1]) for l, r, x in queries]
I need to put the numbers from low to high in an array randomly.
For example given: low = 10, high = 15 a result like [ 12, 13, 10, 14, 11] is good.
This is a simple algorithm: iterate from low to high and try to fill in the empty slots on an array.
const low = 1000
const high = 1010
const diff = high - low
const arr = new Array(diff)
for (var i = low; i < high; i++) {
let success = false
while(!success) {
const index = Math.floor(Math.random() * diff)
if (arr[index] === undefined) {
arr[index] = i
success = true
}
console.log(`${index} was ${success ? 'available' : 'taken'}`)
}
}
console.log(arr)
The problem is: in the end where most of the elements are filled, it is harder to find an unoccupied slot in the array.
My question is: is there an algorithm that constantly generates unique new numbers until all the numbers are consumed?
Another way to think about it is an algorithm that shuffles an array the most efficient and quickest way.
Instead of generating "random" numbers, generate a list of the numbers and shuffle it "randomly" by using something like Fisher-Yates Shuffle:
function getRandomArray(min, max) {
return shuffle([...Array(max - min).keys()].map(i => i + min));
}
function shuffle(array) {
var m = array.length, t, i;
while (m) {
i = Math.floor(Math.random() * m--);
t = array[m];
array[m] = array[i];
array[i] = t;
}
return array;
}
var randomArr = getRandomArray(10, 15);
console.log(randomArr);
Another implementation of Fisher-Yates Shuffle:
const low = 1000
const high = 1010
const delta = high - low
const arr = [...new Array(delta)]
arr.forEach((value, index, arr) => arr[index] = index + low)
const result = []
while (arr.length > 0) {
const index = Math.floor(Math.random() * arr.length)
result.push(arr[index])
arr.splice(index, 1)
}
console.log(result)
For someone looking this in java, just use Collections API.
We have:
Collections.shuffle(yourOriginalArray);
Inputs
Given an array, a maximum value and a current value.
Goal
For each i in array[i], array[i] must add or subtract from current. I can't exactly find out when I should add or subtract to get the following output.
Output
The highest value possible that current can get without getting higher than maximum or less than 0. If not possible return -1.
Question
I came up with the following snippet but it's not correct. If I calculate every possible answer and then find the maximum one the complexity becomes higher than O(n). How can I know when to subtract or add?
function calcMax(array, max, current) {
let output = current;
for (let i = 0; i < array.length; i++) {
if (output + array[i] <= max) {
output += array[i];
} else {
output -= array[i];
}
return output < 0 ? -1 : output;
}
}
console.log(calcMax([5, 3, 7], 16, 5))
Examples
Inputs: ([15, 2, 9, 10], 20, 8).
Correct output: -1
Inputs: ([5, 3, 7], 10, 5).
Correct output: 10 (5 - 5 + 3 + 7)
Inputs: ([5, 3, 7], 16, 5).
Correct output: 14 (5 + 5 - 3 + 7)
The problem seems to me is to traverse two paths - add, subtract.
If consider add, subtract as 2 different paths, it would form a binary tree. For example the array [5, 3, 7] and max = 16, curr = 5 form a binary tree of :
5
0 10
3 7 13
10 0 14 6
where the left child is a subtract and right child is an add. Current value is the node value and element to be added is A[i]
Observe that binary tree is not full because it is constrained by [0, max].
You see that it doesn't have nodes which are less than 0 and greater than maximum.
You could implement a queue based approach to traverse the tree and find the maximum value at last level after all array elements are processed.
Pseudocode would be:
Queue q = new Queue
q.add( current )
int i = 0 //index into array
ans = -1
while ( !q.isEmpty() AND i < A.length )
int qsize = q.size()
for ( int j = 0; j < qsize; j++ )
int currVal = q.poll()
int addValue = currVal + A[i]
int subValue = currVal - A[i]
if ( subValue >= 0 && subValue <= max )
q.add( subValue );
if ( addValue >= 0 && addValue <= max )
q.add( addValue );
i++
//now we processed all array elements, now check max value obtained in the last level if any.
while ( !q.isEmpty )
ans = Math.max( ans, q.poll() )
return ans == current ? -1 : ans;
I came up with a recursive solution. I think it's O(n).
const max = 50;
const current = 20
const array = [20, 30, 4, 14, 16];
let answer = -1;
function calcMax(i, value) {
// Checking the bounds
if (i === array.length) {return value}
if (value > max || value < 0) {return -1}
// With each index compare it with final answer
let r = 0;
if (value + array[i] <= max) {
r = calcMax(i + 1, value + array[i]);
if (r > answer) {
answer = r;
}
}
if (value - array[i] >= 0) {
r = calcMax(i + 1, value - array[i]);
if (r > answer) {
answer = r;
}
}
return r;
}
calcMax(0, current);
console.log(answer);
Example if you have a stack
2
48
1
32
24
12
60
Then after operation it should look like
2
48
60
32
24
12
1
Here is a much better Javascript immplementation:
var stack = [2, 48, 1, 32, 24, 12, 60];
var minPos = stack.indexOf(stack.reduce(function (a, b) { return a <= b ? a : b; }));
var maxPos = stack.indexOf(stack.reduce(function (a, b) { return a >= b ? a : b; }));
stack[minPos] = stack.splice(maxPos, 1, stack[minPos])[0];
Other than the line to set-up an example stack, this approach does 3 things:
Find the position in the array of the 'minimum' number. A reduce function is used to iterate over the array, reducing the array to a single result, which represents the smallest number (See the JS Array.reduce method).
Find the position in the array of the 'maximum' number. This is done similar to the above, but with a reduce function that results in the highest number.
Using the positions we found for 'min' and 'max', swap the elements at these positions in the array.
Here is a JS implementation of a solution.
var myStack = [ 2, 48, 1, 32, 24, 12, 60 ];
var posMax = 0;
var maxValue = myStack[0];
var posMin = 0;
var minValue = myStack[0];
var tempStack = [ ]; // will be constructed, but in the reverse order.
var counter = 0;
do {
var tempElement = myStack.pop();
if(tempElement > maxValue) {
posMax = counter;
maxValue = tempElement;
}
if(tempElement < minValue) {
posMin = counter;
minValue = tempElement;
}
tempStack.push(tempElement);
counter++;
} while(myStack.length != 0);
// Reverse the order of the temp Stack
var tempStack2 = [];
do {
tempStack2.push(tempStack.pop());
} while (tempStack.length != 0)
tempStack = tempStack2;
// Constructing the returned Stack.
var newStack = [];
counter = 0;
do
{
var tempElement = tempStack.pop();
if(counter !== posMin && counter !== posMax) {
newStack.push(tempElement);
}
if(counter === posMax) {
newStack.push(minValue);
}
if(counter === posMin) {
newStack.push(maxValue);
}
counter++;
} while(tempStack.length != 0);
// Reverse the order of the new Stack
var result = [];
do {
result.push(newStack.pop());
} while (newStack.length != 0);
console.log("Final:" + result);
I have an integer array with some finite number of values. My job is to find the minimum difference between any two elements in the array.
Consider that the array contains
4, 9, 1, 32, 13
Here the difference is minimum between 4 and 1 and so answer is 3.
What should be the algorithm to approach this problem. Also, I don't know why but I feel that using trees, this problem can be solved relatively easier. Can that be done?
The minimum difference will be one of the differences from among the consecutive pairs in sorted order. Sort the array, and go through the pairs of adjacent numbers looking for the smallest difference:
int[] a = new int[] {4, 9, 1, 32, 13};
Arrays.sort(a);
int minDiff = a[1]-a[0];
for (int i = 2 ; i != a.length ; i++) {
minDiff = Math.min(minDiff, a[i]-a[i-1]);
}
System.out.println(minDiff);
This prints 3.
You can take advantage of the fact that you are considering integers
to make a linear algorithm:
First pass:
compute the maximum and the minimum
Second pass:
allocate a boolean array of length (max - min + 1), false initialized,
and change the (value - min)th value to true for every value in the array
Third pass:
compute the differences between the indexes of the true valued entries of the boolean array.
While all the answers are correct, I wanted to show the underlying algorithm responsible for n log n run time. The divide and conquer way of finding the minimum distance between the two points or finding the closest points in a 1-D plane.
The general algorithm:
Let m = median(S).
Divide S into S1, S2 at m.
δ1 = Closest-Pair(S1).
δ2 = Closest-Pair(S2).
δ12 is minimum distance across the cut.
Return δ = min(δ1, δ2, δ12).
Here is a sample I created in Javascript:
// Points in 1-D
var points = [4, 9, 1, 32, 13];
var smallestDiff;
function mergeSort(arr) {
if (arr.length == 1)
return arr;
if (arr.length > 1) {
let breakpoint = Math.ceil((arr.length / 2));
// Left list starts with 0, breakpoint-1
let leftList = arr.slice(0, breakpoint);
// Right list starts with breakpoint, length-1
let rightList = arr.slice(breakpoint, arr.length);
// Make a recursive call
leftList = mergeSort(leftList);
rightList = mergeSort(rightList);
var a = merge(leftList, rightList);
return a;
}
}
function merge(leftList, rightList) {
let result = [];
while (leftList.length && rightList.length) {
// Sorting the x coordinates
if (leftList[0] <= rightList[0]) {
result.push(leftList.shift());
} else {
result.push(rightList.shift());
}
}
while (leftList.length)
result.push(leftList.shift());
while (rightList.length)
result.push(rightList.shift());
let diff;
if (result.length > 1) {
diff = result[1] - result[0];
} else {
diff = result[0];
}
if (smallestDiff) {
if (diff < smallestDiff)
smallestDiff = diff;
} else {
smallestDiff = diff;
}
return result;
}
mergeSort(points);
console.log(`Smallest difference: ${smallestDiff}`);
I would put them in a heap in O(nlogn) then pop one by one and get the minimum difference between every element that I pop. Finally I would have the minimum difference. However, there might be a better solution.
This is actually a restatement of the closest-pair problem in one-dimension.
https://en.wikipedia.org/wiki/Closest_pair_of_points_problem
http://www.cs.umd.edu/~samir/grant/cp.pdf
As the Wikipedia article cited below points out, the best decision-tree model of this problem also runs in Ω(nlogn) time.
sharing the simplest solution.
function FindMin(arr) {
//sort the array in increasing order
arr.sort((a,b) => {
return a-b;
});
let min = arr[1]-arr[0];
let n = arr.length;
for (var i=0;i<n;i++) {
let m = arr[i+1] - arr[i];
if(m < min){
m = min;
}
}
return m; // minimum difference.
}
The given problem can easily be solved in O(n) time. Look at the following code that I wrote.
import java.util.Scanner;
public class Solution {
public static void main(String [] args) {
Scanner input = new Scanner(System.in);
int i, minDistance = 999999;
boolean flag = false;
int capacity = input.nextInt();
int arr[] = new int[capacity];
for (i = 0; i < capacity; i++) {
arr[i] = input.nextInt();
}
int firstElement = input.nextInt();
int secondElement = input.nextInt();
int prev = 0;
for (i = 0; i < capacity; i++) {
if (arr[i] == firstElement || arr[i] == secondElement) {
prev = i;
break;
}
}
for (; i < capacity; i++) {
if(arr[i] == firstElement || arr[i] == secondElement) {
if(arr[i] != arr[prev] && minDistance > Math.abs(i - prev)) {
minDistance = Math.abs(i - prev);
flag = true;
prev = i;
} else {
prev = i;
}
}
}
if(flag)
System.out.println(minDistance);
else
System.out.println("-1");
}
}
For those of you who are looking for a one-line python answer (more or less), these are 2 possible solutions:
Python >= 3.10
l = sorted([4, 9, 1, 32, 13])
min(map(lambda x: x[1] - x[0], pairwise(l)))
From Python 3.10 you can use pairwise() that takes an iterable and returns all consecutive pairs of it. After we sort the initial list, we just need to find the pair with the minimum difference.
Python < 3.10
l = sorted([4, 9, 1, 32, 13])
min(map(lambda x: x[1] - x[0], zip(l[:-1], l[1:])))
In this case, we can reproduce the pairwise() method behavior1 using zip() with 2 slices of the same list so that consecutive elements are paired.
1. The actual implementation of pairwise() is probably more efficient in terms of space because it doesn't need to create 2 (shallow) copies of the list. In most cases, this should not be necessary, but you can use itertools.islice to iterate over the list without creating a copy of it. Then, you would write something like zip(islice(a, len(a) - 1), islice(a, 1, None)).
In Python 3 this problem can be simplified by using the module itertools which gives the combinations available for a list. From that list we can find the sum of each combination and find the minimum of those values.
import itertools
arr = [4, 9, 1, 32, 13]
if len(arr) > 1:
min_diff = abs(arr[0] - arr[1])
else:
min_diff = 0
for n1, n2 in itertools.combinations(arr, 2): # Get the combinations of numbers
diff = abs(n1-n2) # Find the absolute difference of each combination
if min_diff > diff:
min_diff = diff # Replace incase a least differnce found
print(min_diff)