Efficient Data structure and Algorithm - Natural Sequence - java

1 - 1
2 - 2,3
3 - 4,5,6
4 - 7,8,9,10
Given any number from 4 to 6 ,I need the output as 3.
Given any number from 7 to 10 ,I need the output as 4.
I need the fastest solution for the above problem to solve an algorithm.
What I could think of is a brute force algorithm :
Given 7:
n-square + n = 7*2 = 14
1 + 1 = 2 < 14
4 + 2 = 6 < 14
9 + 3 = 12 < 14
16+ 4 = 20 >=14 --> So 4
Is there any better approach to arrive at the solution ? OR My approach to the algorithm itself is flawed ?
Brief explanation of the algo :
A,B,C
After every iteration every element becomes increased by one.
A,A,B,B,C,C
Given 3, C will be returned.
Given 4 or 5, A will be returned.
Given 6 or 7, B will be returned.
Given 8 or 9, C will be returned.
Given 10 or 11 or 12, A will be returned.
Given 13 or 14 or 15, B will be returned.
How the solution to the mathematical problem will help solve the algo :
Total number of elements = 3
Given number = 13 (Output to be B)
Divide and Ceiling = Ceil (13/3) = 5 [So 13 falls under when every element has become * 3] (From Mathematical problem : If given number is 5, 3 is to be used)
Starting index of when every element has become * 3 [IS_EQUAL_TO = ] 3 * 3(summation of previous iteration => 1 + 2) + 1 = 10
To Find the index = Ceil(13-10+1/3 (this 3,comes from the mathematical problem) ) = Ceil (4/3) = 2nd index = B

Given number of rows N, the size of the triangle is N(N+1)/2. You are essentially trying to find the least integer N such that N(N+1)/2 >= M, with M given. If you have a function to compute square roots, you can solve this equation in constant time.
N(N+1)/2 >= M, multiply both sides with 2,
N²+N >= 2M, complete the square, take the square root, blablabla
N >= sqrt(2M+1/4)-1/2
Therefore the answer is N = ceil(sqrt(2*M + .25) - .5)

Related

How can I find the stop and start index for a Java vector?

I have a vector that looks like this:
y =
Columns 1 through 19:
1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2
Columns 20 through 38:
2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4
Columns 39 through 57:
4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 5 6
Columns 58 through 67:
6 6 6 6 6 6 6 6 6 6
The vector y is always start at 1 and be counted up. You see that there are lots of same numbers. It's the classes for the samples.
Here we have 1 1 1 1 1 1 1 1 1 1 1 1 = 12 samples for class number 1.
We have 2 2 2 2 2 2 2 2 2 2 2 = 11 samples for class number 2.
My problem here is that I want to find start and stop for every class. For example: Class 1 begins always at index 0 and ends, in this case, at index 11.
Class 2 begins directly after class 1 ends.
Question:
I'm using EJML (Effient Java Matrix Library) and I'm planning to use this function:
C = A.extractMatrix(1,4,2,8)
Which is equal to this MATLAB code:
C = A(2:4,3:8)
But I need to find the start and stop indexes from this y vector. In what index does e.g class 3 stops and starts? Do you have any smart ideas how to do that?
Sure, I could use a for-loop, to do this, but for-loops in Java is quite slow because I'm going to have a very very large y vector.
Suggestions?
Edit:
Here is an suggestion. Is that good, or could it be done better?
private void startStopIndex(SimpleMatrix y, int c, Integer[] startStop) {
int column = y.numCols();
startStop[0] = startStop[1] + 1; // Begin at the next class
for(int i = startStop[0]; i < column; i++) {
if(y.get(i) != c) {
break;
}else {
startStop[1] = i;
}
}
}
Assuming that we are calling the method from:
Integer[] startStop = new Integer[2];
for(int i = 0; i < c; i++) {
startStopIndex(y, c, startStop);
}
If you want to do it faster then binary search is your friend. Threw this together really quick and it does things in O(log n) time, where as a linear search does it in O(n). It's pretty basic and assumes your data looks pretty much like you describe it. Feed it weird data and it will break.:
int[] breakPoints(int[] arr, int low, int high){
int[] rtrn = new int[high];
for(int i=low;i<high;i++){
rtrn[i]=binarySearch(arr, i, 0, arr.length-1);
}
return rtrn;
}
int binarySearch(int[] arr, int k, int start, int end){
int mid = (start+end)/2;
if(mid==arr.length){
return -1;
}
if(arr[mid]==k && arr[mid+1]==k+1){
return mid+1; //or just mid if you want before breakpoint
}
if(arr[mid]<=k){
return binarySearch(arr, k, mid+1, end);
}
return binarySearch(arr, k, start, mid-1);
}
You'd call it like this:
int[] data = {1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,5,5,6,6,6,6};
int[] bp = breakPoints(data,1,6);
//return 0, 3, 8, 13, 16, 18
I think there is a name for this, but I can't remember what it might be, but you start looking for the next boundary with an accelerating search, and use a binary search after that.
You know the numbers are in ascending order, and there are potentially a lot of the same number, so you start by checking the next element. But instead of keep going 1 step at a time, you accelerate and step 2, 4, 8, 16, ... until you find a higher number.
Once you've found a higher number, you've gone too far, but the last step had the initial number, so you know the boundary is somewhere between the last two steps, and you then apply a binary search for the boundary.
Once you've fund the boundary, you start over stepping 1, 2, 4, ... for the next boundary.
If you expect most numbers to have about the same number of occurrences, you could keep a running average count, and make the first step with that average, to get a running start.
I'll leave it to you to actually code this.
The below is in MATLAB. the for loop will go through each unique value stored in x1 and then find the first and last occurrence of that value.
x = [ 1 1 1 2 2 3 3 3 3 3 4 4 4 4 5 5 5 ]
x1 = unique(x)'
for k1 = 1:length(x1)
x1(k1,2:3) = [find(x == x1(k1,1),1,"first"), find(x == x1(k1,1),1,"last")];
end
the above code yields x1 to be a 3 column matrix
1 1 3
2 4 5
3 6 10
4 11 14
5 15 17

Addition of two numbers, twist is that the length of number can be very large [duplicate]

This question already has answers here:
How to add two numbers of any length in java?
(8 answers)
Closed 5 years ago.
Today I had an interview and the interviewer asked to make a program for addition of two numbers, I get shocked how can he give a simple question but the question is different
the length of two number can be anything (10,20,30 or even 1000 etc.)
if you convert it to int,double,long double if the number is greater than their range than the answer can be wrong.
Please help me for the question.
You can always take the two numbers in arrays (i.e. arrays have digits of the numbers as elements) and add them as we add manually i.e. start from one's digit and store the carry if it's present then do the same for ten's digit, then hundred's digit and so on.
Say you want to add 123 and 329.
X = 123, X[] = [1,2,3]
Y = 329, Y[] = [3,2,9]
You start with one's digit (the rightmost or last element) and add the elements of both X and Y arrays and add carry to it (initially set to 0). If the addition comes out to be greater than 10, set carry = sum / 10 (since we are adding each element, this carry shall always be either 0 or 1) and the addition to add [i] = sum % 10. Repeat till all the elements of smaller array are over. Then add the carry to remaining elements of larger array continuing the above logic.
carry = 0
Step 1 : 3 + 9 + carry (0) = 5, carry => 12 / 10 = 1, add => 12 % 10 = 2
Step 2 : 2 + 2 + carry (2) = 6, carry => 6 / 10 = 0, add => 6 % 10 = 6
Step 3 : 3 + 1 + carry (0) = 4, carry => 4 / 10 = 0, add => 4 % 10 = 4
Ans = 462
Obviously the array storing sum may have one digit extra so take care of that as well.

Effiecient Algorithm for Finding if a Very Big Number is Divisible by 7

So this was a question on one of the challenges I came across in an online competition, a few days ago.
Question:
Accept two inputs.
A big number of N digits,
The number of questions Q to be asked.
In each of the question, you have to find if the number formed by the string between indices Li and Ri is divisible by 7 or not.
Input:
First line contains the number consisting on N digits. Next line contains Q, denoting the number of questions. Each of the next Q lines contains 2 integers Li and Ri.
Output:
For each question, print "YES" or "NO", if the number formed by the string between indices Li and Ri is divisible by 7.
Constraints:
1 ≤ N ≤ 105
1 ≤ Q ≤ 105
1 ≤ Li, Ri ≤ N
Sample Input:
357753
3
1 2
2 3
4 4
Sample Output:
YES
NO
YES
Explanation:
For the first query, number will be 35 which is clearly divisible by 7.
Time Limit: 1.0 sec for each input file.
Memory Limit: 256 MB
Source Limit: 1024 KB
My Approach:
Now according to the constraints, the maximum length of the number i.e. N can be upto 105. This big a number cannot be fitted into a numeric data structure and I am pretty sure thats not the efficient way to go about it.
First Try:
I thought of this algorithm to apply the generic rules of division to each individual digit of the number. This would work to check divisibility amongst any two numbers, in linear time, i.e. O(N).
static String isDivisibleBy(String theIndexedNumber, int divisiblityNo){
int moduloValue = 0;
for(int i = 0; i < theIndexedNumber.length(); i++){
moduloValue = moduloValue * 10;
moduloValue += Character.getNumericValue(theIndexedNumber.charAt(i));
moduloValue %= divisiblityNo;
}
if(moduloValue == 0){
return "YES";
} else{
return "NO";
}
}
But in this case, the algorithm has to also loop through all the values of Q, which can also be upto 105.
Therefore, the time taken to solve the problem becomes O(Q.N) which can also be considered as Quadratic time. Hence, this crossed the given time limit and was not efficient.
Second Try:
After that didn't work, I tried searching for a divisibility rule of 7. All the ones I found, involved calculations based on each individual digit of the number. Hence, that would again result in a Linear time algorithm. And hence, combined with the number of Questions, it would amount to Quadratic Time, i.e. O(Q.N)
I did find one algorithm named Pohlman–Mass method of divisibility by 7, which suggested
Using quick alternating additions and subtractions: 42,341,530
-> 530 − 341 = 189 + 42 = 231 -> 23 − (1×2) = 21 YES
But all that did was, make the time 1/3rd Q.N, which didn't help much.
Am I missing something here? Can anyone help me find a way to solve this efficiently?
Also, is there a chance this is a Dynamic Programming problem?
There are two ways to go through this problem.
1: Dynamic Programming Approach
Let the input be array of digits A[N].
Let N[L,R] be number formed by digits L to R.
Let another array be M[N] where M[i] = N[1,i] mod 7.
So M[i+1] = ((M[i] * 10) mod 7 + A[i+1] mod 7) mod 7
Pre-calculate array M.
Now consider the expression.
N[1,R] = N[1,L-1] * 10R-L+1 + N[L,R]
implies (N[1,R] mod 7) = (N[1,L-1] mod 7 * (10R-L+1mod 7)) + (N[L,R] mod 7)
implies N[L,R] mod 7 = (M[R] - M[L-1] * (10R-L+1 mod 7)) mod 7
N[L,R] mod 7 gives your answer and can be calculated in O(1) as all values on right of expression are already there.
For 10R-L+1 mod 7, you can pre-calculate modulo 7 for all powers of 10.
Time Complexity :
Precalculation O(N)
Overall O(Q) + O(N)
2: Divide and Conquer Approach
Its a segment tree solution.
On each tree node you store the mod 7 for the number formed by digits in that node.
And the expression given in first approach can be used to find the mod 7 of parent by combining the mod 7 values of two children.
The time complexity of this solution will be O(Q log N) + O(N log N)
Basically you want to be able to to calculate the mod 7 of any digits given the mod of the number at any point.
What you can do is to;
record the modulo at each point O(N) for time and space. Uses up to 100 KB of memory.
take the modulo at the two points and determine how much subtracting the digits before the start would make e.g. O(N) time and space (once not per loop)
e.g. between 2 and 3 inclusive
357 % 7 = 0
3 % 7 = 3 and 300 % 7 = 6 (the distance between the start and end)
and 0 != 6 so the number is not a multiple of 7.
between 4 and 4 inclusive
3577 % 7 == 0
357 % 7 = 0 and 0 * 10 % 7 = 0
as 0 == 0 it is a multiple of 7.
You first build a list of digits modulo 7 for each number starting with 0 offset (like in your case, 0%7, 3%7, 35%7, 357%7...) then for each case of (a,b) grab digits[a-1] and digits[b], then multiply digits[b] by 1-3-2-6-4-5 sequence of 10^X modulo 7 defined by (1+b-a)%6 and compare. If these are equal, return YES, otherwise return NO. A pseudocode:
readString(big);
Array a=[0]; // initial value
Array tens=[1,3,2,6,4,5]; // quick multiplier lookup table
int d=0;
int l=big.length;
for (int i=0;i<l;i++) {
int c=((int)big[i])-48; // '0' -> 0, and "big" has characters
d=(3*d+c)%7;
a.push(d); // add to tail
}
readInt(q);
for (i=0;i<q;i++) {
readInt(li);
readInt(ri); // get question
int left=(a[li-1]*tens[(1+ri-li)%6])%7;
if (left==a[ri]) print("YES"); else print("NO");
}
A test example:
247761901
1
5 9
61901 % 7=0. Calculating:
a = [0 2 3 2 6 3 3 4 5 2]
li = 5
ri = 9
left=(a[5-1]*tens[(1+9-5)%6])%7 = (6*5)%7 = 30%7 = 2
a[ri]=2
Answer: YES

Partition 2d array in sub-arrays

I have to partition a 2d array (the size is given by the user) into sub-arrays given an input number by the user. The code i Wrote works well for most of the instances by there are some that I need some help with.
I do this by taking the square root of the input number. So for example:
If the user inserts [10, 10, 9] it means that this is a 10 * 10 array with 9 sub-arrays. Taking the square root of 9 works fine because it gives 3.
If the user inserts [8, 6, 6] it takes the square root of 6 and rounds it up for the longest side (which gives 3) and rounds it down for the shortest (which is 2). So 3 * 2 = 6. It also works fine.
Then there is a situation like 8. The square root of 8 gives 3 and 2. So the array is partitioned into 6 sub-arrays. Is there another way to find a better partitioning for numbers like 8, 14? Or is there a way to find the optimal distribution for such numbers (e.g. 2 * 4 = 8, 2 * 7 = 14)?
You can calculate them a bit different way:
int x = Math.round(Math.sqrt(n));
int y = Math.round(1. * n / x);
Thus you'll receive:
n = 8 => x = 3, y = 3
n = 14 => x = 4, y = 4
What you need to do is find the two nearest factors to the square root. Try this code:
long n = 14;
long y = 0;
long x = Math.round(Math.sqrt(n));
while(true){
if (n % x == 0) {
y = n/x;
break;
}
else {
x--;
}
}
You might also like to put in some error checking to cope with input errors. e.g. n<1.

Modulus division when first number is smaller than second number

I apologize if this is a simple question but I'm having trouble grasping the concept of modulus division when the first number is smaller than the second number. For example when 1 % 4 my book says the remainder is 1. I don't understand how 1 is the remainder of 1 % 4. 1 / 4 is 0.25. Am I thinking about modulus division incorrectly?
First, in Java, % is the remainder (not modulo) operator, which has slightly different semantics.
That said, you need to think in terms of integer-only division, as if there were no fractional values. Think of it as storing items that cannot be divided: you can store zero items of size 4 in a storage of overall capacity one. Your remaining capacity after storing the maximum number of items is one. Similarly, 13%5 is 3, as you can fit 2 complete items of size 5 in a storage of size 13, and the remaining capacity is 13 - 2*5 = 3.
If you divide 1 by 4, you get 0 with a remainder of 1. That's all the modulus is, the remainder after division.
I am going to add a more practical example to what "Jean-Bernard Pellerin" already said.
It is correct that if you divide 1 by 4 you get 0 but, Why when you do 1 % 4 you have 1 as result?
Basically it is because this:
n = a / b (integer), and
m = a % b = a - ( b * n )
So,
a b n = a/b b * n m = a%b
1 4 0 0 1
2 4 0 0 2
3 4 0 0 3
4 4 1 0 0
5 4 1 4 1
Conclusion: While a < b, the result of a % b will be "a"
Another way to think of it as a representation of your number in multiples of another number. I.e, a = n*b + r, where b>r>=0. In this sense your case gives 1 = 0*4 + 1. (edit: talking about positive numbers only)
I think you are confused between %(Remainder) and /(Division) operators.
When you say %, you need to keep dividing the dividend until you get the remainder 0 or possible end. And what you get in the end is called Remainder.
When you say /, you divide the dividend until the divisor becomes 1. And the end product you get is called Quotient
Another nice method to clear things up,
In modulus, if the first number is > the second number, subtract the second number from the first until the first number is less than the second.
17 % 5 = ?
17 - 5 = 12
12 % 5 = ?
12 - 5 = 7
7 % 5 = ?
7 - 5 = 2
2 % 5 = 2
Therefore 17 % 5, 12 % 5, 7 % 5 all give the answer of 2.
This is because 2 / 5 = 0 (when working with integers) with 2 as a remainder.

Categories