Saturday, September 23, 2017

Codility - Lesson 10 Prime and composite numbers - 3. Peaks

Source Link:
https://codility.com/programmers/lessons/10-prime_and_composite_numbers/peaks/

Question:
A non-empty zero-indexed array A consisting of N integers is given.
A peak is an array element which is larger than its neighbors. More precisely, it is an index P such that 0 < P < N − 1,  A[P − 1] < A[P] and A[P] > A[P + 1].

For example, the following array A:
A[0] = 1 A[1] = 2 A[2] = 3 A[3] = 4 A[4] = 3 A[5] = 4 A[6] = 1 A[7] = 2 A[8] = 3 A[9] = 4 A[10] = 6 A[11] = 2 
has exactly three peaks: 3, 5, 10.
We want to divide this array into blocks containing the same number of elements. More precisely, we want to choose a number K that will yield the following blocks:
  • A[0], A[1], ..., A[K − 1],
  • A[K], A[K + 1], ..., A[2K − 1],
    ...
  • A[N − K], A[N − K + 1], ..., A[N − 1].
What's more, every block should contain at least one peak. Notice that extreme elements of the blocks (for example A[K − 1] or A[K]) can also be peaks, but only if they have both neighbors (including one in an adjacent blocks).

The goal is to find the maximum number of blocks into which the array A can be divided.
Array A can be divided into blocks as follows:
  • one block (1, 2, 3, 4, 3, 4, 1, 2, 3, 4, 6, 2). This block contains three peaks.
  • two blocks (1, 2, 3, 4, 3, 4) and (1, 2, 3, 4, 6, 2). Every block has a peak.
  • three blocks (1, 2, 3, 4), (3, 4, 1, 2), (3, 4, 6, 2). Every block has a peak. Notice in particular that the first block (1, 2, 3, 4) has a peak at A[3], because A[2] < A[3] > A[4], even though A[4] is in the adjacent block.
However, array A cannot be divided into four blocks, (1, 2, 3), (4, 3, 4), (1, 2, 3) and (4, 6, 2), because the (1, 2, 3) blocks do not contain a peak. Notice in particular that the (4, 3, 4) block contains two peaks: A[3] and A[5]. The maximum number of blocks that array A can be divided into is three.

Write a function: 

class Solution { public int solution(int[] A); }

that, given a non-empty zero-indexed array A consisting of N integers, returns the maximum number of blocks into which A can be divided. If A cannot be divided into some number of blocks, the function should return 0.

For example, given:
A[0] = 1 A[1] = 2 A[2] = 3 A[3] = 4 A[4] = 3 A[5] = 4 A[6] = 1 A[7] = 2 A[8] = 3 A[9] = 4 A[10] = 6 A[11] = 2 
the function should return 3, as explained above.
Assume that:
  • N is an integer within the range [1..100,000];
  • each element of array A is an integer within the range [0..1,000,000,000].
Complexity:
  • expected worst-case time complexity is O(N*log(log(N)));
  • expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.

My Solution:
Notes:
1. main idea:
// 1) find all the peaks, and put them into a List
// 2) try to divide the array into a number of groups,
// and check if all the groups have at least one peak
//--> if yes, return the "number of groups"   
2. use "List" to store all the peaks
List<Integer> peaksIndexList = new ArrayList<>();
3. find the peaks (and store them)
for(int i=1; i<A.length-1; i++){
if( A[i-1]<A[i] && A[i]>A[i+1] ){ // A[i] > A[i-1], A[i] > A[i+1]
peaksIndexList.add(i);
}

4. check the number of Blocks
// from the "biggest possible number" to smaller number
int N = A.length;
for(int numBlocks =N; numBlocks >=1; numBlocks--){
if( N % numBlocks ==0){ // it is divisible
int blockSize = N / numBlocks; 
int ithOkBlock =0; // the ith block has peak(s)
// test all the peaks 
// if a peak is found in the ith block
// then, go to the (i+1)th block
for(int peaksIndex : peaksIndexList){
if( peaksIndex/blockSize == ithOkBlock){ // peak in the ith block
ithOkBlock++; // go to check (i+1)th block
}
}
if(ithOkBlock == numBlocks){
return numBlocks;
}
}
}

Codility - Lesson 10 Prime and composite numbers - 2. CountFactors

Source Link:
https://codility.com/programmers/lessons/10-prime_and_composite_numbers/count_factors/

Question:
A positive integer D is a factor of a positive integer N if there exists an integer M such that N = D * M.

For example, 6 is a factor of 24, because M = 4 satisfies the above condition (24 = 6 * 4).

Write a function: 

class Solution { public int solution(int N); }

that, given a positive integer N, returns the number of its factors.

For example, given N = 24, the function should return 8, because 24 has 8 factors, namely 1, 2, 3, 4, 6, 8, 12, 24. There are no other factors of 24.

Assume that:
  • N is an integer within the range [1..2,147,483,647].
Complexity:
  • expected worst-case time complexity is O(sqrt(N));
  • expected worst-case space complexity is O(1).
My Solution:
Notes:
1. main idea:
// check from 1 to "sqrt_of_N"  
// then, taking its pair into consideration
// ---> numFactor = numFactor * 2;  
2. 
int numFactor =0; // number of factors
int sqrtN = (int) Math.sqrt(N);

3. check if i is a factor or not (by using N % i ==0)
for(int i=1; i <= sqrtN; i++){
if(N % i ==0){  
numFactor++;
}
}
4. add its pair
numFactor = numFactor * 2;
5. be careful: check if "sqrtN * sqrtN == N"
if( sqrtN * sqrtN == N){ 
numFactor = numFactor -1; // minus one: avoid double counting
}
return numFactor;   

Codility - Lesson 10 Prime and composite numbers - 1. MinPerimeterRectangle

Source Link:
https://codility.com/programmers/lessons/10-prime_and_composite_numbers/min_perimeter_rectangle/

Question:
An integer N is given, representing the area of some rectangle.
The area of a rectangle whose sides are of length A and B is A * B, and the perimeter is 2 * (A + B).
The goal is to find the minimal perimeter of any rectangle whose area equals N. The sides of this rectangle should be only integers.

For example, given integer N = 30, rectangles of area 30 are:
  • (1, 30), with a perimeter of 62,
  • (2, 15), with a perimeter of 34,
  • (3, 10), with a perimeter of 26,
  • (5, 6), with a perimeter of 22.
Write a function: 

class Solution { public int solution(int N); }

that, given an integer N, returns the minimal perimeter of any rectangle whose area is exactly equal to N.

For example, given an integer N = 30, the function should return 22, as explained above.

Assume that:
  • N is an integer within the range [1..1,000,000,000].
Complexity:
  • expected worst-case time complexity is O(sqrt(N));
  • expected worst-case space complexity is O(1).

My Solution:
Notes:
1. main idea:
// try to find the one "closest to sqrt(N)"
int sqrtN = (int) Math.sqrt(N);
int perimeter = (1 * 2) + (N * 2); // perimeter = (A*2)+(B*2) 
2. from the one closest to sqrt(N)
for(int i = sqrtN; i > 0; i--){
if( N % i ==0){ // key point: "N % i ==0"
int A = i;
int B = N/i;
perimeter = (A * 2) + (B * 2);
break; // be careful: break from the for-loop
}
}
return perimeter;  

Codility - Lesson 10 Prime and composite numbers

Source Link:
https://codility.com/programmers/lessons/10-prime_and_composite_numbers/

Some Notes:
People have been analyzing prime numbers since time immemorial. A prime number is a natural number greater than 1 that has exactly two divisors (1 and itself).



In the above picture the primes are highlighted in white.


10.1. Counting divisors

Based on one divisor, we can find the symmetric divisor. One of these two divisors is less than or equal to sqr(n).Thus, iterating through all the numbers from 1 to sqr(n) allows us to find all the divisors.

10.1: Counting the number of divisors — O(sqr(n)).
1 def divisors(n):

2 i = 1
3 result = 0
4 while (i * i < n):
5 if (n % i == 0):
6 result += 2
7 i += 1
8 if (i * i == n):
9 result += 1
10 return result



10.2. Primality test

10.2: Primality test — O(sqr(n)).
1 def primality(n):
2 i = 2
3 while (i * i <= n):
4 if (n % i == 0):
5 return False
6 i += 1
7 return True


We assume that 1 is neither a prime nor a composite number, so the above algorithm works only for n ­ >= 2.

Codility - Lesson 9 Maximum Slice Problem - 3. MaxSliceSum

Source Link:
https://codility.com/programmers/lessons/9-maximum_slice_problem/max_slice_sum/

Question:
A non-empty zero-indexed array A consisting of N integers is given. A pair of integers (P, Q), such that 0 ≤ P ≤ Q < N, is called a slice of array A. The sum of a slice (P, Q) is the total of A[P] + A[P+1] + ... + A[Q].

Write a function: 

class Solution { public int solution(int[] A); }

that, given an array A consisting of N integers, returns the maximum sum of any slice of A.

For example, given array A such that:
A[0] = 3 A[1] = 2 A[2] = -6 A[3] = 4 A[4] = 0 
the function should return 5 because:
  • (3, 4) is a slice of A that has sum 4,
  • (2, 2) is a slice of A that has sum −6,
  • (0, 1) is a slice of A that has sum 5,
  • no other slice of A has sum greater than (0, 1).
Assume that:
  • N is an integer within the range [1..1,000,000];
  • each element of array A is an integer within the range [−1,000,000..1,000,000];
  • the result will be an integer within the range [−2,147,483,648..2,147,483,647].
Complexity:
  • expected worst-case time complexity is O(N);
  • expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified. 

My Solution:
Notes:
1. elegant solution
// not using "Math.max( 0, maxEndingHere + A[i])"
// Instead, using "Math.max( A[i], maxEndingPrevious + A[i] )" 
2. initial setting A[0]
int maxEndingPrevious = A[0];
int maxEndingHere = A[0];
int maxSoFar = A[0];
// note: for i=0, it will return A[0] (also for "one element" cases) 
3. 
for(int i = 1; i < A.length; i++){
maxEndingHere = Math.max(A[i], maxEndingPrevious + A[i]); // <--- key point~!!
maxEndingPrevious = maxEndingHere;
maxSoFar = Math.max(maxSoFar, maxEndingHere); // update the max (be careful)
}
return maxSoFar; // can be used for "all negative" cases   

Codility - Lesson 9 Maximum Slice Problem - 2. MaxProfit

Source Link:
https://codility.com/programmers/lessons/9-maximum_slice_problem/max_profit/

Question:
A zero-indexed array A consisting of N integers is given. It contains daily prices of a stock share for a period of N consecutive days. If a single share was bought on day P and sold on day Q, where 0 ≤ P ≤ Q < N, then the profit of such transaction is equal to A[Q] − A[P], provided that A[Q] ≥ A[P]. Otherwise, the transaction brings loss of A[P] − A[Q].

For example, consider the following array A consisting of six elements such that:
A[0] = 23171 A[1] = 21011 A[2] = 21123 A[3] = 21366 A[4] = 21013 A[5] = 21367 
If a share was bought on day 0 and sold on day 2, a loss of 2048 would occur because A[2] − A[0] = 21123 − 23171 = −2048. If a share was bought on day 4 and sold on day 5, a profit of 354 would occur because A[5] − A[4] = 21367 − 21013 = 354. Maximum possible profit was 356. It would occur if a share was bought on day 1 and sold on day 5.

Write a function, 

class Solution { public int solution(int[] A); }

that, given a zero-indexed array A consisting of N integers containing daily prices of a stock share for a period of N consecutive days, returns the maximum possible profit from one transaction during this period. The function should return 0 if it was impossible to gain any profit.

For example, given array A consisting of six elements such that:
A[0] = 23171 A[1] = 21011 A[2] = 21123 A[3] = 21366 A[4] = 21013 A[5] = 21367 
the function should return 356, as explained above.

Assume that:
  • N is an integer within the range [0..400,000];
  • each element of array A is an integer within the range [0..200,000].
Complexity:
  • expected worst-case time complexity is O(N);
  • expected worst-case space complexity is O(1), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.

My Solution:
Notes:
1. main idea (One Pass Solution):
// We can maintain two variables  
// 1) minprice (key point~!!)
// 2) maxprofit (corresponding to the smallest valley)  
2. two variables (and initial setting)
int minPrice = A[0];
int maxProfit =0;
3. one pass solution
for(int i=1; i<A.length; i++){
if(A[i] < minPrice) // case 1: from high to low
minPrice = A[i];
else{ // case 2: from low to high
int curProfit = A[i] - minPrice;
if(curProfit > maxProfit) // update max profit
maxProfit = curProfit;
}
}
return maxProfit;   

Codility - Lesson 9 Maximum Slice Problem - 1. MaxDoubleSliceSum

Source Link:
https://codility.com/programmers/lessons/9-maximum_slice_problem/max_double_slice_sum/

Question:
A non-empty zero-indexed array A consisting of N integers is given.
A triplet (X, Y, Z), such that 0 ≤ X < Y < Z < N, is called a double slice.
The sum of double slice (X, Y, Z) is the total of A[X + 1] + A[X + 2] + ... + A[Y − 1] + A[Y + 1] + A[Y + 2] + ... + A[Z − 1].

For example, array A such that:
A[0] = 3 A[1] = 2 A[2] = 6 A[3] = -1 A[4] = 4 A[5] = 5 A[6] = -1 A[7] = 2 
contains the following example double slices:
  • double slice (0, 3, 6), sum is 2 + 6 + 4 + 5 = 17,
  • double slice (0, 3, 7), sum is 2 + 6 + 4 + 5 − 1 = 16,
  • double slice (3, 4, 5), sum is 0.
The goal is to find the maximal sum of any double slice.

Write a function: 

class Solution { public int solution(int[] A); }

that, given a non-empty zero-indexed array A consisting of N integers, returns the maximal sum of any double slice.

For example, given:
A[0] = 3 A[1] = 2 A[2] = 6 A[3] = -1 A[4] = 4 A[5] = 5 A[6] = -1 A[7] = 2 
the function should return 17, because no double slice of array A has a sum of greater than 17. Assume that:
  • N is an integer within the range [3..100,000];
  • each element of array A is an integer within the range [−10,000..10,000].
Complexity:
  • expected worst-case time complexity is O(N);
  • expected worst-case space complexity is O(N), beyond input storage (not counting the storage required for input arguments).
Elements of input arrays can be modified.

My Solution:
Notes:
1. (X, Y, Z)
// 1st slice: A[X+1] + ... + A[Y-1]  
// 2nd slice: A[Y+1] + ... + A[Z-1]
// Key Point:
// The array will be split at "Y"    
2. main idea: if the middle point is "Y", find "maxLeft" and "maxRight" 
int maxLeft[] = new int[A.length];
int maxRight[] = new int[A.length]; 
3. find "maxLeft"
// maxLeft[i] is the maximum sum "contiguous subsequence" ending at index i  
// note: because it is "contiguous", we only need the ending index (important)
for(int i=1; i< A.length ;i++){ // be careful: from i=1 (because of maxLeft[i-1])
maxLeft[i] = Math.max(0, maxLeft[i-1]+A[i] ); //golden slice algorithm: Math.max(0, maxLeft[i-1]+A[i] )
   
4. find "maxRight"
// maxRight[i] is the maximum sum "contiguous subsequence" starting at index i  
// note: because it is "contiguous", we only need the starting index (important)
for(int i=A.length-2; i >=0; i--){ // be careful: from i=A.length-2 (because of maxLeft[i+1])
maxRight[i] = Math.max(0, maxRight[i+1]+A[i] ); //golden slice algorithm: Math.max(0, maxRight[i+1]+A[i] )
   
5. find the maximum of "maxLeft + maxRight"
int maxDoubleSlice =0;
for(int i=1; i < A.length-1; i++){ // where "i" means "Y" in this problem
if(maxLeft[i-1] + maxRight[i+1] > maxDoubleSlice) // be careful: left end at "i-1" and right begins at "i+1"
maxDoubleSlice = maxLeft[i-1] + maxRight[i+1]; // be careful: "not" maxLeft[i] + maxRight[i]
  
return maxDoubleSlice; 

Codility - Lesson 16 Greedy algorithms - 2. MaxNonoverlappingSegments

Source Link: https://app.codility.com/programmers/lessons/16-greedy_algorithms/max_nonoverlapping_segments/ Question: Located on a line ...