Find the number of pairs whose sum is divisible by k? - numbers

Given a value of k. Such that k<=100000
We have to print the number of pairs such that sum of elements of each pair is divisible by k.
under the following condition first element should be smaller than second, and both element should be less than 109.

I've found a solution, let a and b numbers such that (a+b)%k=0 then we have to find that pairs (a,b), where a<b, so let's count how many pairs (a,b) satisfy the condition that a+b=k, for example if k=3 0+3=3, 1+2=3, 2+1=3, 3+0=3 there are 4 pairs but only 2 pairs which is (K+1)/2 (integer division) so similar for find the pairs (a,b) which sum is 2k, 3k,.. nk, and the solution will be (k+1)/2 + (2k+1)/2 + (3k+1)/2 + ... + (nk+1)/2, and that is equal to (k*n*(n+1)/2 + n)/2 with time complexity O(1), take care in the case if n*k=2*10^9, because a can't be more than 10^9 for the given constraint.

Solution in O(N) time and O(N) space using hash map.
The concept is as follows:
If (a+b)%k=0 where
a=k*SOME_CONSTANT_1+REMAINDER_1
b=k*SOME_CONSTANT_2+REMAINDER_2
then (REMAINDER_1 +REMAINDER_2 )%k will surely be 0
so for an array (4,2,3,31,14,16,8) and k =5 if you have some information like below , you can figure out which all pairs sum %k =0
Note that, Bottom most row consist of all the remainders from 0 to k-1 and all the numbers corresponding to it.
Now all you need to do is move both the pointer towards each other until they meet. If both the pointers locations have number associated with it their sum%k will be 0
To solve it, you can keep track of all the remainder you have seen so far by using hash table
create a hash map Map<Integer, List>.
Pre-populate its keys with 0 to k-1;
iterate over array and put remainder of each number in the map with Key = remainder and put the actual number in the list,
Iterate over the key set using two pointers moving each other. And sum += listSizeAsPointedByPointer1 * listSizeAsPointedByPointer2

One way is brute force:
int numPairs = 0;
for (i = 0; i < 10e9; i++)
{
for (j = i+1; j < 10e9; j++)
{
int sum = i + j;
if (sum % k == 0) numPairs++;
}
}
return numPairs;
I'll leave it up to you to optimize this for performance. I can think of at least one way to significantly speed this up.

Some psuedo-code to get you started. It uses the brute-force technique you say you tried, but maybe something was wrong in your code?
max = 1000000000
numberPairs = 0
for i = 1 to max - 2 do
for j = i + 1 to max - 1 do
if (i + j) mod k = 0 then
numberPairs = numberPairs + 1
end if
end do
end do

Related

Find all numbers which are equal to the sum of the factorial of their digits

How can Find all numbers (e.g. 145= 1! + 4! + 5! = 1 + 24 + 120 = 145.)
which are equal to the sum of the factorial of their digits, by MATLAB?
I want to chop off digits, add the factorial of the digits together and compare it with the original number. If factorial summation be equal to original number, this numbers is on of the solution and must be keep. I can't code my idea, How can I code it? Is this true?
Thanks
The main reason that I post this answer is that I can't leave the use of eval in the previous answer without a decent alternative
Here is a small function to check this for any given (integer) n:
isFact = #(n) n==sum(factorial(int2str(n)-'0'));
Explanation:
int2str(n)-'0': "chop off digits"
sum(factorial(...)): "add the factorial of the digits together"
n==...: "compare it with the original number"
You can now plug it in a loop to find all the numbers between 1 to maxInt:
maxInt = 100000; % just for the example
solution = false(1,maxInt); % preallocating memory
for k = 1:maxInt
solution(k) = isFact(k);
end
find(solution) % find all the TRUE indices
The result:
ans =
1 2 145 40585
The loop above was written to be simple. If you look for further efficiency and flexibility (like not checking all the numbers between 1 to maxInt and checking array in any shape), you can change it to:
% generating a set of random numbers with no repetitions:
Vec2Check = unique(randi(1000,1,1000)); % you can change that to any array
for k = 1:numel(Vec2Check)
if isFact(Vec2Check(k))
Vec2Check(k) = Vec2Check(k)+0.1;
end
end
solution = Vec2Check(Vec2Check>round(Vec2Check))-0.1
The addition of 0.1 serves as a 'flag' that marks the numbers that isFact returns true for them. We then extract them by comparing the vector to it's rounded vertsion.
You can even go with a one-line solution:
solution = nonzeros(arrayfun(#(n) n.*(n==sum(factorial(int2str(n)-'0'))),Vec2Check))
The following snippet finds the numbers up to 1000 satisfying this condition.
numbers = [];
for i=1:1000
number_char = int2str(i);
sum = 0;
for j=1:length(number_char)
sum = sum+ factorial(eval(number_char(j)));
end
if (sum == i)
numbers(end+1) = i;
end
end
disp(numbers)
This should yield:
1 2 145
Note that if (log10(n)+1)*9! is less than n, then there is no number satisfying the condition larger than n.

Count values from range in Matlab

I want to count the number of values in the array. I have a code which works:
Range = [1:10^3];% [1:10^6];
N = 10^2;% 10^8
Data = randi([Range(1),Range(end)],N,1);
Counts = nan(numel(Range),1);
for iRange = 1:numel(Range)
Counts(iRange) = sum(Data==Range(iRange));
end
Could you help me to make this code faster?
I feel that it should be via unique or hist, but I could not find a solution.
N = histcounts(Data,Range)
gives me 999 numbers instead of 1000.
As Ander Biguri stated at a comment, histcounts is what you seek.
The function counts the number of values of X (Data in your example), are found at every bin between two edges, where bins defined as such:
The value X(i) is in the kth bin if edges(k) ≤ X(i) < edges(k+1).
While the last bin also includes the right edges.
This means:
For N values, you need N+1 edges.
Each bin should start at the value you want it to include (1 between 1:2, 2 between 2:3, etc).
In your example:
Counts = histcounts(Data,Range(1):(Range(end)+1))';
I wanted to point out an issue with this code:
Counts = nan(numel(Range),1);
for iRange = 1:numel(Range)
Counts(iRange) = sum(Data==Range(iRange));
end
It shows a single loop, but == and sum work over all elements in the array, making this really expensive compared to a loop that doesn't do so, especially if N is large:
Counts = zeros(numel(Range),1);
for elem = Data(:).'
Counts(elem) = Counts(elem) + 1;
end

sorting numbers

How to generate a combination of 5 elements out of 8 elements where the final list should have only the combination of 5 elements which are two or more elements different from each other?
I started replacing the elements with numbers from 1-8 and generated the initial list using:
x = 1:8;
v = permn(x,5);
The initial list consists 8^5 numbers. e. g. 11111,11112,11113.....88888.
If I take the starting seed as 11111, the sorted numbers can be like, 11122, 11123 and so on. Because these numbers are atleast two element difference with 11111. But then from this second list, both 11122 and 11123 can't go to the next list because they have only one element difference.
The final list should have all these unique set of elements which has atleast two or more element difference with each other.
Can someone please help me to implement the condition?
An iterative solution have and order o(n^2) with n=size(v,1):
m=1
while m < size(v,1)
part2 = v(m+1:end, :);
%compare each row with the following rows e.g. part2.
u = bsxfun(#ne, v(m,:), part2);
%check if number of different elements greater than 1
s = sum(u,2) > 1;
%extract those rows and append to the current rows
v= [v(1:m,:); part2(s,:)];
m = m + 1;
end
The final v will have unique elements.
Create a bubble sort with inner and outer loop, compare elements from inner loop and outer loop based on rank (rank = 1 if two or more elements differ) thereafter swap elements if rank <> 0.
Pseudo Code
For I= 0 to (N-1)
For J= I+1 to N
If Rank(Array(I), Array(J)) <> 0 Then
Swap(Array(I), Array(J))
End
End
End

How does this prime number generation method work?

I want to figure out what the background of this code is, specifically, the reason of the commands written. I understand everything until the first line of the for loop, but then I got lost with the second line:
N= input('Enter your number: ');
primes = 2:N;
p=2;
while (p <= N)
for i = 2*p:p:N
primes(i - 1) = 0;
end;
p = p + 1;
end
primes = primes(primes > 0)
Can someone help me to understand this code please?
The code implements the Sieve of Eratosthenes to find the primes numbers.
It generated the array primes which contains the integer numbers from 2 to N
primes = 2:N
The while loop iterates across the integer values
while (p <= N)
At each iteration of the while loop in the for loop, the multiples of the current value of p are generated within the definition of the set of values of the loop index variable i
2*p:p:N
at each iteration of the for loop the element of the primes array in the position i is set to 0
At the end of the for loop, all the multiples of the current value of p are then set to 0
primes(i - 1) = 0;
The process is then repeated for all the integers values between 2 and N by the while loop.
At the end of the while loop the array primes will contains the prime numbers between 2 and N.
primes = primes(primes > 0)
This instruction finds the numbers different from 0 in the array primes and re-defines the array itself by assigning to it all all the numbers different from 0 or, that is the same. it removes from the array primes all of the 0s.
By definition the multiple of a given number is not a prime number.
Hope this helps.

Vectorising while loop MATLAB insertion sort

I need to use vectorization to remove the nested while loop inside my for loop, for making an insertion sort program. I am not allowed to have a while loop inside my for loop, I must do it "such that there are no while or for loops in your function except the outermost for loop."
Here is the code I have currently
function insertsort(array)
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
while (j >= 1) && (array(j) > value)
array(j+1) = array(j);
j = j-1;
end
array(j+1) = value;
end %forLoop
disp(array);
end %insertionSort
This will do it:
array = [2 1 3 2 1]
for i = 2:length(array)
value = array(i);
j = i - 1;
array_j=array(1:j);
array_j_indices=cumsum(array_j>value);
[~,n]=find(array_j_indices==1);
newArray=array;
array(n+1:i)=array_j(array_j>value);
j=j-max(array_j_indices);
array(j+1) = value;
end %forLoop
disp(array);
Explanation: First take elements from j to 1 in an array, since while loop will eventually scan through those elements. Find which of the elements are greater than the value and take its cumulative sum which will tell us how many elements are greater than the value. Because that is the amount we have to decrement j by. Now, find where the first 1 occurs (i.e. the first index at which the number is greater than value, since we have to shift every element to the right by 1 position from that index). After that, decrement j and put the value back. You are done.
Is there a reason you don't want to use the built in sort ?
ans=sort(array)
will do it.