Related
I am new and learning Data structure and algorithm, I need help to solve this question
The best of an array having N elements is defined as sum of best of all elements of Array. The best of element A[i] is defined in the following manner
a: The best of element A[i] is 1 if, A[i-1]<A[i]<A[i+1]
b: The best of element A[i] is 2 if, A[i]> A[j] for j ranging from 0 to n-1
and A[i]<A[h] for h ranging from i+1 to N-1
Write program to find best of array
Note- A[0] and A[N-1] are excluded to find best of array, all elements are unique
Input - 2,1,3,9,20,7,8
Output - 3
The best of element 3 is 2 and 9 is 1. For rest element it is 0. Hence 2+1 =3
This is what I tried so far -
public static void main (String [] args) {
int [] A = {2,1,3,9,20,7,8};
int result = 0;
for(int i=1; i<A.length-2; i++) {
if(A[i-1] < A[i] && A[i]< A[i+1] ) {
result += 1;
}else if(A[i]>A[j] && A[i]<A[h]){
result +=2;
}else {
result+=0;
}
}
}
Note how the phrase:
A[i]> A[j] for j ranging from 0 to n-1
simply means: If the current element is not the Minimum of the array. Hence, if you find the minimum at the beginning, this condition can be changed into a much simpler and lightweight condition:
Let m be the minimum of the array, then if A[i] > m
So you don't need to do a linear search every iteration --> Less time complexity.
Now you have the problem with a complexity of O(N^2), ..which can be reduced further.
Regarding
and A[i]<A[h] for h ranging from i+1 to N-1
Get the maximum element from 2 to N-1. Then at every iteration, check if the current element is less than the maximum. If so, consider it while composing the score, otherwise, that means the current element is the maximum, in this case, re-calculate the maximum element from i+1 to N-1.
The worst case scenario is to find the maximum is always at index i where the array is already sorted in descending order.
Whereas the best case scenario is if the maximum is always the last element, hence the overall complexity is reduced to O(N).
Regarding
A[i-1]<A[i]<A[i+1]
This is straightforward, you simply compare the elements reside at those three indices at every iteration.
Implementation
Before anything, the following are important notes:
The result you've got in your example isn't correct as elements 3 and 9 both fulfill both conditions, so each should score either 1 or 2, but cannot be one with score of 1 and another with score of 2. Hence the overall score should be either 1+1 = 2 or 2 + 2 = 4.
I implemented this algorithm in Java (although I prefer Python), as I could guess it from your code snippet.
import java.util.Arrays;
public class ArrayBest {
private static int[] findMinMax(Integer [] B) {
// find minimum and the maximum: Time Complexity O(n log(n))
Integer[] b = Arrays.copyOf(B, B.length);
Arrays.sort(b);
return new int []{b[0], b[B.length-1]};
}
public static int find(Integer [] A) {
// Exclude the first and last elements
int N = A.length;
Integer [] B = Arrays.copyOfRange(A, 1, N-1);
N -= 2;
// find minimum and the maximum: Time Complexity O(n log(n))
// min at index 0, and max at index 1
int [] minmax = findMinMax(B);
int result = 0;
// start the search
for (int i=0; i<N-1; i++) {
// start with first condition : the easier
if (i!=0 && B[i-1]<B[i] && B[i]<B[i+1]) {
result += 1;
}else if (B[i] != minmax[0]) { // Equivalent to A[i]> A[j] : j in [0, N-1]
if (B[i] < minmax[1]) { // if it is less than the maximum
result += 2;
}else { // it is the maximum --> re-calculate the max over the range (i+1, N)
int [] minmax_ = findMinMax(Arrays.copyOfRange(B, i+1, N));
minmax[1] = minmax_[1];
}
}
}
return result;
}
public static void main(String[] args) {
Integer [] A = {2,1,3,9,7,20,8};
int res = ArrayBest.find(A);
System.out.println(res);
}
}
Ignoring the first sort, the best case scenario is when the last element is the maximum (i.e, at index N-1), hence time complexity is O(N).
The worst case scenario, is when the array is already sorted in a descending order, so the current element that is being processed is always the maximum, hence at each iteration the maximum should be found again. Consequently, the time complexity is O(N^2).
The average case scenario depends on the probability of how the elements are distributed in the array. In other words, the probability that the element being processed at the current iteration is the maximum.
Although it requires more study, my initial guess is as follows:
The probability of any i.i.d element to be the maximum is simply 1/N, and that is at the very beginning, but as we are searching over (i+1, N-1), N will be decreasing, hence the probability will go like: 1/N, 1/(N-1), 1/(N-2), ..., 1. Counting the outer loop, we can write the average complexity as O(N (1/N + 1/(N-1), 1/(N-2), + ... +1)) = O(N (1 + 1/2 + 1/3 + ... + 1/N)) where its asymptotic upper bound (according to Harmonic series) is approximately O(N log(N)).
For example if the array is arr[] = {4, 2, 6, 1, 5},
and k = 3, then the output should be 4 2 1.
It can be done in O(nk) steps and O(1) space.
Firstly, find the kth smallest number in kn steps: find the minimum; store it in a local variable min; then find the second smallest number, i.e. the smallest number that is greater than min; store it in min; and so on... repeat the process from i = 1 to k (each time it's a linear search through the array).
Having this value, browse through the array and print all elements that are smaller or equal to min. This final step is linear.
Care has to be taken if there are duplicate values in the array. In such a case we have to increment i several times if duplicate min values are found in one pass. Additionally, besides min variable we have to have a count variable, which is reset to zero with each iteration of the main loop, and is incremented each time a duplicate min number is found.
In the final scan through the array, we print all values smaller than min, and up to count values exactly min.
The algorithm in C would like this:
int min = MIN_VALUE, local_min;
int count;
int i, j;
i = 0;
while (i < k) {
local_min = MAX_VALUE;
count = 0;
for (j = 0; j < n; j++) {
if ((arr[j] > min || min == MIN_VALUE) && arr[j] < local_min) {
local_min = arr[j];
count = 1;
}
else if ((arr[j] > min || min == MIN_VALUE) && arr[j] == local_min) {
count++;
}
}
min = local_min;
i += count;
}
if (i > k) {
count = count - (i - k);
}
for (i = 0, j = 0; i < n; i++) {
if (arr[i] < min) {
print arr[i];
}
else if (arr[i] == min && j < count) {
print arr[i];
j++;
}
}
where MIN_VALUE and MAX_VALUE can be some arbitrary values such as -infinity and +infinity, or MIN_VALUE = arr[0] and MAX_VALUE is set to be maximal value in arr (the max can be found in an additional initial loop).
Single pass solution - O(k) space (for O(1) space see below).
The order of the items is preserved (i.e. stable).
// Pseudo code
if ( arr.size <= k )
handle special case
array results[k]
int i = 0;
// init
for ( ; i < k, i++) { // or use memcpy()
results[i] = arr[i]
}
int max_val = max of results
for( ; i < arr.size; i++) {
if( arr[i] < max_val ) {
remove largest in results // move the remaining up / memmove()
add arr[i] at end of results // i.e. results[k-1] = arr[i]
max_val = new max of results
}
}
// for larger k you'd want some optimization to get the new max
// and maybe keep track of the position of max_val in the results array
Example:
4 6 2 3 1 5
4 6 2 // init
4 2 3 // remove 6, add 3 at end
2 3 1 // remove 4, add 1 at end
// or the original:
4 2 6 1 5
4 2 6 // init
4 2 1 // remove 6, add 1 -- if max is last, just replace
Optimization:
If a few extra bytes are allowed, you can optimize for larger k:
create an array size k of objects {value, position_in_list}
keep the items sorted on value:
new value: drop last element, insert the new at the right location
new max is the last element
sort the end result on position_in_list
for really large k use binary search to locate the insertion point
O(1) space:
If we're allowed to overwrite the data, the same algorithm can be used, but instead of using a separate array[k], use the first k elements of the list (and you can skip the init).
If the data has to be preserved, see my second answer with good performance for large k and O(1) space.
First find the Kth smallest number in the array.
Look at https://www.geeksforgeeks.org/kth-smallestlargest-element-unsorted-array-set-2-expected-linear-time/
Above link shows how you can use randomize quick select ,to find the kth smallest element in an average complexity of O(n) time.
Once you have the Kth smallest element,loop through the array and print all those elements which are equal to or less than Kth smallest number.
int small={Kth smallest number in the array}
for(int i=0;i<array.length;i++){
if(array[i]<=small){
System.out.println(array[i]+ " ");
}
}
A baseline (complexity at most 3n-2 for k=3):
find the min M1 from the end of the list and its position P1 (store it in out[2])
redo it from P1 to find M2 at P2 (store it in out[1])
redo it from P2 to find M3 (store it in out[0])
It can undoubtedly be improved.
Solution with O(1) space and large k (for example 100,000) with only a few passes through the list.
In my first answer I presented a single pass solution using O(k) space with an option for single pass O(1) space if we are allowed to overwrite the data.
For data that cannot be overwritten, ciamej provided a O(1) solution requiring up to k passes through the data, which works great.
However, for large lists (n) and large k we may want a faster solution. For example, with n=100,000,000 (distinct values) and k=100,000 we would have to check 10 trillion items with a branch on each item + an extra pass to get those items.
To reduce the passes over n we can create a small histogram of ranges. This requires a small storage space for the histogram, but since O(1) means constant space (i.e. not depending on n or k) I think we're allowed to do that. That space could be as small as an array of 2 * uint32. Histogram size should be a power of two, which allows us to use bit masking.
To keep the following example small and simple, we'll use a list containing 16-bit positive integers and a histogram of uint32[256] - but it will work with uint32[2] as well.
First, find the k-th smallest number - only 2 passes required:
uint32 hist[256];
First pass: group (count) by multiples of 256 - no branching besides the loop
loop:
hist[arr[i] & 0xff00 >> 8]++;
Now we have a count for each range and can calculate which bucket our k is in.
Save the total count up to that bucket and reset the histogram.
Second pass: fill the histogram again,
now masking the lower 8 bits and only for the numbers belonging in that range.
The range check can also be done with a mask
After this last pass, all values represented in the histogram are unique
and we can easily calculate where our k-th number is.
If the count in that slot (which represents our max value after restoring
with the previous mask) is higher than one, we'll have to remember that
when printing out the numbers.
This is explained in ciamej's post, so I won't repeat it here.
---
With hist[4] and a list of 32-bit integers we would need 8 passes.
The algorithm can easily be adjusted for signed integers.
Example:
k = 7
uint32_t hist[256]; // can be as small as hist[2]
uint16_t arr[]:
88
258
4
524
620
45
440
112
380
580
88
178
Fill histogram with:
hist[arr[i] & 0xff00 >> 8]++;
hist count
0 (0-255) 6
1 (256-511) 3 -> k
2 (512-767) 3
...
k is in hist[1] -> (256-511)
Clear histogram and fill with range (256-511):
Fill histogram with:
if (arr[i] & 0xff00 == 0x0100)
hist[arr[i] & 0xff]++;
Numbers in this range are:
258 & 0xff = 2
440 & 0xff = 184
380 & 0xff = 124
hist count
0 0
1 0
2 1 -> k
... 0
124 1
... 0
184 1
... 0
k - 6 (first pass) = 1
k is in hist[2], which is 2 + 256 = 258
Loop through arr[] to display the numbers <= 258 in preserved order.
Take care of possible duplicate highest numbers (hist[2] > 1 in this case).
we can easily calculate how many we have to print of those.
Further optimization:
If we can expect k to be in the lower ranges, we can even optimize this further by using the log2 values instead of fixed ranges:
There is a single CPU instruction to count the leading zero bits (or one bits)
so we don't have to call a standard log() function
but can call an intrinsic function instead.
This would require hist[65] for a list with 64-bit (positive) integers.
We would then have something like:
hist[ 64 - n_leading_zero_bits ]++;
This way the ranges we have to use in the following passes would be smaller.
Given a 1-indexed array A of size N, the distance between any
2 indices of this array i and j is given by |i−j|. Now, given this information, I need to find for every index i (1≤i≤N), an index j, such that 1≤j≤N, i≠j, and GCD(A[i],A[j])>1.
If there are multiple such candidates for an index i, have to find index j, such that the distance between i and j is minimal. If there still exist multiple candidates, print the minimum j satisfying the above constraints.
Example:
Array(A) 2 3 4 9 17
Output : 3 4 1 2 -1
Note: array size can be as large as 2*10^5.
and each array element can take max value 2*10^5 and min value 1.
I should be able to calculate this in 1 second at most.
Here is my code, but its exceeding time limit. Is there a way to optimize it.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class GCD {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
int[] a = new int[n+1];
StringBuilder sb =new StringBuilder("");
String[] array = br.readLine().trim().split(" ");
for(int i=1; i<=n; i++){
a[i] = Integer.parseInt(array[i-1]);
}
int c,d;
l1: for(int i=1; i<=n; i++){
c = i-1;
d = i+1;
while((c>0||d<=n)){
if(c>0){
if(GCD(a[i],a[c])>1){
sb.append(c+" ");
continue l1;
}
}
if(d<=n){
if(GCD(a[i],a[d])>1){
sb.append(d+" ");
continue l1;
}
}
c--;
d++;
}
sb.append("-1 ");
}
System.out.println(sb);
}
static long GCD(int a, int b){
if(b==0)
return a;
return GCD(b, a%b);
}
}
You know the problem can be solved in one second. You know that array can have 200,000 elements. Comparing 200,000 elements with 200,000 elements takes 40 billion comparisons. If you're lucky your computer does 3 billion operations per second. You see that comparing 200,000 elements with 200,000 elements isn't going to work. (That would happen in the simple case where all array elements are equal to 1). So optimizing your code isn't going to help.
So move your mind away from the way the problem is posed. It asks to find j so that gcd (a [i], a [j]) != 1. What it really means is to find j so that a [j] has a prime factor in common with a [i]. And that j needs to be the largest j < i or the smallest j > i.
The numbers are small, less than 200,000. So you can find all the different prime factors of a a [i] very quickly.
So first you create an array "index": For each prime number p <= 200,000, index [p] is the index j of the last array element a [j] that you examined which had the prime factor p, or -1 if you didn't find any. You also create an array "solution": For each i that you examined, it contains the closest number so far or -1.
Iterate through the array for i = 1 to n: For each a [i], find all prime factors. For every factor p: If j = index [p] > 0 then a [j] is also divisible by p, so gcd (a [i], a [j]) > 1. Doing that you get the largest j < i with gcd (a [i], a [j]) > 1. Also update the array index as you find prime factors.
But also if you find that a [i] and a [j] have a common factor, then the solution that you stored for j might be wrong because it only considered indices less than j, so update solution as well. Pseudo-code:
Create array "index" filled with -1.
Create array "solution" filled with -1.
for all i
for all prime factors p of a [i]
let j = index [p]
index [p] = j
if j >= 0
if solution [i] = -1
solution [i] = j
else if j > solution [i]
solution [i] = j
if solution [j] = -1
solution [j] = i
else if solution [j] < j && i-j < j - solution [j]
solution [j] = i
print solution
You can see it doesn't matter at all how far the array element with a common factor is away. The execution time is a very small number times the number of prime factors, plus the time for finding the factors, which is worst if all elements are large primes. So all you need to do is find all the factors of any number < 200,000 in say 3-4 microseconds. Should be easy. You are allowed to create a table of prime numbers up to 500 before you start.
To run this under 1 second, your algorithm should be θ(N) or θ(N * log(N)), N<2*10^5. One way to do this can be:
Let us find all the factors except 1, of all the numbers, in 1 iteration of the array. Complexity = θ(N) * θ(GCD) = θ(N * log(N))
Make a hashmap, with key = the factor we just found and value = sorted array of indices of elements in input whose factors they are. (The arrays in hash map are made in order, so no need for explicit sorting. number of factors<θ(log(N))) Complexity = θ(N * log(N))
Now we iterate over the elements and in each element, iterate over the factors and for each factor, we find from the hash map where this factor is present in the nearest indices using binary search. We select the nearest value for all the factors for each element and provide this as the answer. Complexity = θ (N * log(N) * log(log(N))).
The question:
"Write an algorithm that given an array A and an integer value k it returns the value true if there are two different integers in A that sum to k, and it returns false otherwise."
My pseudocode:
Input: array A of size n with value k
Output: true if two different integers in A sum to k, false otherwise
Algorithm ArraySum(A, n, k)
for (i=0, i<n, i++)
for (j=i+1, j<n, j++)
if (A[i]+A[j]=k)
return true
return false
Have I written this algorithm correctly? Are there any mistakes I'm just not seeing?
There are two solutions in my mind regarding the problem
First Solution
1.Make an empty hash
2.Mark all number in array in hash
for each i (Array A){
hash[i] = 1;
}
3.Just run an O(n) loop
for each i (Array A)
if( hash[ k - i ] )
print "solution i and k-i"
That will give you O(n) complexity
Second Solution
1.Sort Array
2.Run an O(n) loop over the sorted Array
for each i (Array A)
binary_search( Array, k - i); [log n operation]
That will give you O(n logn) complexity.
If two different integers means A[i], A[j] where i != j rather than A[i] != A[j], your pseudocode is correct.
It is looks like as some case of knapsack problem.
For your case (only two numbers), may be will be better to sort your array to reduce number of comparision (A[i]+A[j]=k).
For example:
you have sorted array [1 3 5 8 10 12 14 20 50 60 100]
sum of two numbers must be equal to 30
Then you can write
while(a[i] <= 30) {
while(a[i] + a[j] <= 30) {
// ...
i++;
j++;
}
}
Given an Array arr of size 100000, each element 0 <= arr[i] < 100. (not sorted, contains duplicates)
Find out how many triplets (i,j,k) are present such that arr[i] ^ arr[j] ^ arr[k] == 0
Note : ^ is the Xor operator. also 0 <= i <= j <= k <= 100000
I have a feeling i have to calculate the frequencies and do some calculation using the frequency, but i just can't seem to get started.
Any algorithm better than the obvious O(n^3) is welcome. :)
It's not homework. :)
I think the key is you don't need to identify the i,j,k, just count how many.
Initialise an array size 100
Loop though arr, counting how many of each value there are - O(n)
Loop through non-zero elements of the the small array, working out what triples meet the condition - assume the counts of the three numbers involved are A, B, C - the number of combinations in the original arr is (A+B+C)/!A!B!C! - 100**3 operations, but that's still O(1) assuming the 100 is a fixed value.
So, O(n).
Possible O(n^2) solution, if it works: Maintain variable count and two arrays, single[100] and pair[100]. Iterate the arr, and for each element of value n:
update count: count += pair[n]
update pair: iterate array single and for each element of index x and value s != 0 do pair[s^n] += single[x]
update single: single[n]++
In the end count holds the result.
Possible O(100 * n) = O(n) solution.
it solve problem i <= j <= k.
As you know A ^ B = 0 <=> A = B, so
long long calcTripletsCount( const vector<int>& sourceArray )
{
long long res = 0;
vector<int> count(128);
vector<int> countPairs(128);
for(int i = 0; i < sourceArray.size(); i++)
{
count[sourceArray[i]]++; // count[t] contain count of element t in (sourceArray[0]..sourceArray[i])
for(int j = 0; j < count.size(); j++)
countPairs[j ^ sourceArray[i]] += count[j]; // countPairs[t] contain count of pairs p1, p2 (p1 <= p2 for keeping order) where t = sourceArray[i] ^ sourceArray[j]
res += countPairs[sourceArray[i]]; // a ^ b ^ c = 0 if a ^ b = c, we add count of pairs (p1, p2) where sourceArray[p1] ^ sourceArray[p2] = sourceArray[i]. it easy to see that we keep order(p1 <= p2 <= i)
}
return res;
}
Sorry for my bad English...
I have a (simple) O(n^2 log n) solution which takes into account the fact that i, j and k refer to indices, not integers.
A simple first pass allow us to build an array A of 100 values: values -> list of indices, we keep the list sorted for later use. O(n log n)
For each pair i,j such that i <= j, we compute X = arr[i]^arr[j]. We then perform a binary search in A[X] to locate the number of indices k such that k >= j. O(n^2 log n)
I could not find any way to leverage sorting / counting algorithm because they annihilate the index requirement.
Sort the array, keeping a map of new indices to originals. O(nlgn)
Loop over i,j:i<j. O(n^2)
Calculate x = arr[i] ^ arr[j]
Since x ^ arr[k] == 0, arr[k] = x, so binary search k>j for x. O(lgn)
For all found k, print mapped i,j,k
O(n^2 lgn)
Start with a frequency count of the number of occurrences of each number between 1 and 100, as Paul suggests. This produces an array freq[] of length 100.
Next, instead of looping over triples A,B,C from that array and testing the condition A^B^C=0,
loop over pairs A,B with A < B. For each A,B, calculate C=A^B (so that now A^B^C=0), and verify that A < B < C < 100. (Any triple will occur in some order, so this doesn't miss triples. But see below). The running total will look like:
Sum+=freq[A]*freq[B]*freq[C]
The work is O(n) for the frequency count, plus about 5000 for the loop over A < B.
Since every triple of three different numbers A,B,C must occur in some order, this finds each such triple exactly once. Next you'll have to look for triples in which two numbers are equal. But if two numbers are equal and the xor of three of them is 0, the third number must be zero. So this amounts to a secondary linear search for B over the frequency count array, counting occurrences of (A=0, B=C < 100). (Be very careful with this case, and especially careful with the case B=0. The count is not just freq[B] ** 2 or freq[0] ** 3. There is a little combinatorics problem hiding there.)
Hope this helps!