Maximum Product Subarray
Given an array that contains both positive and negative integers, find the subarray of the maximum product .
Examples:
Input: arr[] = {6, -3, -10, 0, 2}
Output: The subarray is {6, -3, -10}
Input: arr[] = {-1, -3, -10, 0, 60}
Output: The subarray is {60}
Input: arr[] = {-2, -3, 0, -2, -40}
Output: The subarray is {-2, -40}
Note: Finding the Max Product is done as using the kadane algo where i tried to reuse it for finding sub array but not able to break the part of finding the start index, finding end index is easy. end index is where res < max.
public int maxProductSubArray(int arr[], int len) {
int res = arr[0];
int max = arr[0];
int min = arr[0];
for (int i = 1; i < len; i++) {
int temp = max;
max = Math.max(Math.max(max * arr[i], min * arr[i]), arr[i]);
min = Math.min(Math.min(temp * arr[i], min * arr[i]), arr[i]);
res = Math.max(res, max);
}
return res;
}
but not able to break the problem to find the SubArray.
There are several possible ways to solve this problem:
Brute-Force
Divide-and-Conquer
Backtracking
I will only show you the Brute-Force-Solution. It is not the fastest solution, but in my opinion the most clear and easily understandable solution:
public class SubArray {
public static int findMax(int[] num) {
int max = num[0];
int start = 0;
int end = 0;
for(int i = 0; i < num.length; i++) { //Iterating over every possible starting position
for(int j = i; j < num.length; j++) { //Iterating over every possible end position
int multiply = 1;
for(int k = i; k <= j; k++) { //Multiply from start to end
multiply *= num[k];
}
if(max < multiply) { //Did we find a new maximum?
max = multiply;
start = i;
end = j;
}
}
}
System.out.print("The subarray is {"); //Print subarray with highest product
for(int i = start; i <= end; i++) {
System.out.print(num[i]);
if(i < end) {
System.out.print(", ");
}
}
System.out.println("}");
return max;
}
public static void main(String[] args) {
int[] array = {6, -3, -10, 0, 2} ;
int max = findMax(array);
System.out.println("Maximal product is: " + max);
}
}
This problem can be efficiently solved by divide and conquer.
Assume you want to solve the problem for a subarray [l, r]; Then, assuming c = (l + r) / 2 the solution is either subarray in [l, c], or in [c + 1, r], or in some subarray containing c and c + 1.
Then let's define a function f(l, r) returning the answer for subsegment; Then, to compute this function, first recursively call f(l, c) and f(c + 1, r) and pick the maximum as the temporary answer. Then compute multiplications of segments [c, c], then [c - 1, c] and so on (using multiplication of [c - k, c] = multiplication of [c - k + 1, c] * array[c - k]) and compute maximum and minimum multiplications across all such segments. Do the same for segments to the right of c ([c + 1, c + 1], [c + 1, c + 2] and so on) Then, the answer will be either a temporary answer, of multiplication of maximums or multiplication of minimums or multiplication of minimum and maximum and vice versa (minimum times maximum is required if such multiplication would be negative). Return the maximum across these four values or the temporary answer as the function result.
If it is necessary, instead of returning just the value of multiplication function can also return the segment where these value is reached.
This solution uses Θ(n log n) time and Θ(n) space.
Given an array of integers, I'm trying to find the longest subset (powerset) with sum equal to k using the lease possible time complexity.
e.g. if inputArr= [1, 2, 8, 1, 1, 7] and k= 10, then the output should be 4 since the longest subset with sum equals to 10 is [1, 1, 1, 7].
Edit: I might've forgotten an important detail; the elements of the array are all positive and non-zero.
I used this algorithm that I found on geeksforgeeks:
https://www.geeksforgeeks.org/finding-all-subsets-of-a-given-set-in-java/
The code works fine, but the only problem that I have is with the execution time. I am supposed to submit this online, and when I submit it the execution terminates due to timeout.
int maxSubLength=0;
for (int i = 1; i < (1<<n); i++) //n is the length of inputArr
{
int sum=0, length=0;
for (int j = 0; j < n; j++)
if ((i & (1 << j)) > 0)
{
sum+=inputArr[j];
length++;
if (sum>k)
break;
}
if (sum==k)
maxSubLength=Math.max(maxSubLength, length);
}
Is there any faster algorithm? I tried a recursive one and it didn't help.
We can solve this with dynamic programming in O(n*k) time and O(k) space. JavaScript code:
function f(A, K){
let m = new Array(K + 1).fill(0)
for (let a of A){
for (let k=K; k>=a; k--)
if (m[k - a])
m[k] = Math.max(m[k], 1 + m[k - a])
m[a] = Math.max(m[a], 1)
}
return m[K]
}
var A = [1, 2, 8, 1, 1, 7]
var K = 10
console.log(f(A, K))
public static int[] bubbleSort(int[] inputArray){
for(int i = 0; i < inputArray.length - 1; i++ ){
int tempa = inputArray[i];
int tempb = inputArray[i + 1];
if(inputArray[i] > inputArray[i + 1]){
inputArray[i] = tempb;
inputArray[i + 1] = tempa;
i = 0;
System.out.println(Arrays.toString(inputArray));
}
}
return inputArray;
}
This implementation takes [20, 35, -15, 7, 55, 1, -22] and returns [20, -22, -15, 1, 7, 35, 55]. Sorts everything but the first index.
Why ... skips the first index?
Because you set i = 0 inside the loop, but then the loop will do i++, so the first element is only examined on the first iteration, not on any "restart".
To restart correctly, use i = -1 so the i++ will make restart happen at i = 0, not at i = 1.
That will make the code work, but it is inefficient to restart immediately upon swapping two elements, because you will repeatedly recheck the beginning of the array.
I worked with a Codility problem provided below,
A non-empty array A consisting of N integers is given.
A peak is an array element which is larger than its neighbours. More precisely, it is an index P such that 0 < P < N − 1 and A[P − 1] < A[P] > A[P + 1].
For example, the following array A:
A[0] = 1
A[1] = 5
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 four peaks: elements 1, 3, 5 and 10.
You are going on a trip to a range of mountains whose relative heights are represented by array A, as shown in a figure below. You have to choose how many flags you should take with you. The goal is to set the maximum number of flags on the peaks, according to certain rules.
Flags can only be set on peaks. What's more, if you take K flags, then the distance between any two flags should be greater than or equal to K. The distance between indices P and Q is the absolute value |P − Q|.
For example, given the mountain range represented by array A, above, with N = 12, if you take:
two flags, you can set them on peaks 1 and 5;
three flags, you can set them on peaks 1, 5 and 10;
four flags, you can set only three flags, on peaks 1, 5 and 10.
You can, therefore, set a maximum of three flags in this case.
Write a function:
class Solution { public int solution(int[] A); }
that, given a non-empty array A of N integers, returns the maximum number of flags that can be set on the peaks of the array.
For example, the following array A:
A[0] = 1
A[1] = 5
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..400,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);
expected worst-case space complexity is O(N) (not counting the storage required for input arguments).
I walk through the solution provided below,
public static int solution(int[] A) {
int N = A.length;
/*
* P = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
int[] P = nextPeak(A);
int i = 1;
int result = 0;
while ((i - 1) * i <= N) {
int index = 0;
int flags = 0;
while (index < N && flags < i) {
/*
* P = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
index = P[index];
if (index == -1) {
break;
}
flags += 1;
index += i;
}
/*
* maximize the number of flags for the whole segment
* */
result = Math.max(result, flags);
i++;
}
return result;
}
/*
* A = [1, 1, 3, 3, 5, 5, 10, 10, 10, 10, 10, -1]
* */
public static int[] nextPeak(int[] P) {
int N = P.length;
ArrayList<Integer> peaks = new ArrayList<Integer>();
for (int i = 1; i < P.length - 1; i++) {
if (P[i] > P[i - 1] && P[i] > P[i + 1]) {
peaks.add(i);
}
}
int[] A = new int[N];
A[N - 1] = -1;
for (int i = N - 2; i >= 0; i--) {
if (peaks.contains(i)) {
A[i] = i;
} else {
A[i] = A[i + 1];
}
}
return A;
}
Generally, I understand the computation but fail to see where do we meet the condition if you take K flags, then the distance between any two flags should be greater than or equal to K.
I imagine this is inside the while condition of (i-1)*i <= N but unable to comprehend it properly. Would anyone kindly explain it to me?
Your answer is index += i; combined with the condition flags < i in the while loop.
They work the solution in reverse: walking K steps at a time, insert at most K flags.
The set [1,2,3,…,n] contains a total of n! unique permutations.
By listing and labeling all of the permutations in order,
We get the following sequence (ie, for n = 3 ) :
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
For example, given n = 3, k = 4, ans = "231".
There are multiple solutions out there. But all of them uses either factorial or there complexity is larger than O(n) such as O(n!). If you use factorial and find the number at the position by k/(n-1)!, the problem comes when n is large(n = 100). Here as n is large, (n-1)! overflows and becomes 0. In result, I am getting a divide by zero error...any solution or algorithm for that?
Here is my code:
public class KthPermutation {
public String getPermutation(int n, int k) {
// initialize all numbers
ArrayList<Integer> numberList = new ArrayList<Integer>();
for (int i = 1; i <= n; i++) {
numberList.add(i);
}
int fact = 1; // set factorial of n-1
for (int i = 1; i <= n-1; i++) {
fact = fact * i;
}
if ((long) k > (long) fact * n) {
k = (int) ((long) k - (long) (fact * n));
}
k--; // set k to base 0
StringBuilder result = new StringBuilder();
result = getP(result, numberList, n, k, fact);
return result.toString();
}
public static StringBuilder getP(StringBuilder result,
ArrayList<Integer> numberList, int n, int k, int fact) {
if (numberList.size() == 1 || n == 1) {
result.append(numberList.get(0));
return result; // return condition
}
int number = (k / fact) + 1 ;
result.append(numberList.get(number - 1));
numberList.remove(number - 1);
k = k % fact; // update k
fact = fact / (n - 1);
n--;
return getP(result, numberList, n, k, fact);
}
}
So if I'm reading the question correctly, you want to find the kth permutation, preferrably without using BigIntegers, provided k is not large enough to require a BigInteger.
If we look at the sequence
1 2 3
1 3 2
2 1 3
2 3 1
3 1 2
3 2 1
We can rewrite it so that the number in each position is an index into a list of the numbers that haven't appeared so far on the line:
0 0 0
0 1 0
1 0 0
1 1 0
2 0 0
2 1 0
So for example "2, 0, 0" means start with the list "1, 2, 3", then take the third (because we are indexing from zero), which is a 3, then take the first of the remaining digits "1, 2" which is a 1, then the first of the remaining digit, which is "2". So it produces "3, 1, 2".
To generate these indices, go from right to left and divide k by 1! for the rightmost two places, then 2! then 3! then 4! etc, and then modulo the result with the number of possible indices in that position, which is 1 for the rightmost, 2 for the second-rightmost etc. You don't have to calculate the factorial each time because you can keep a running product.
You can break out of the loop as soon as k divided by the factorial is zero, so you only have to compute factorials up until roughly the size of k multiplied by the last place in which k divided by the factorial is non-zero. If k is too large, you need to switch to BigIntegers.
Once you have the indices it's pretty straightforward to use them to generate the permutation.
Code (k starts from 0, so to find the first pass 0, not 1):
static public void findPermutation(int n, int k)
{
int[] numbers = new int[n];
int[] indices = new int[n];
// initialise the numbers 1, 2, 3...
for (int i = 0; i < n; i++)
numbers[i] = i + 1;
int divisor = 1;
for (int place = 1; place <= n; place++)
{
if((k / divisor) == 0)
break; // all the remaining indices will be zero
// compute the index at that place:
indices[n-place] = (k / divisor) % place;
divisor *= place;
}
// print out the indices:
// System.out.println(Arrays.toString(indices));
// permute the numbers array according to the indices:
for (int i = 0; i < n; i++)
{
int index = indices[i] + i;
// take the element at index and place it at i, moving the rest up
if(index != i)
{
int temp = numbers[index];
for(int j = index; j > i; j--)
numbers[j] = numbers[j-1];
numbers[i] = temp;
}
}
// print out the permutation:
System.out.println(Arrays.toString(numbers));
}
Demo
output:
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]
10000000th permutation for n = 100:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 92, 98, 96, 90, 91, 100, 94, 97, 95, 99, 93]
The indices for k'th permutation (used in the answer to this question) are the factoradic representation of k and can be calculated without using factorial or running product.
public static List<Integer> toFactoradic(int x) {
List<Integer> result = new ArrayList<>();
for(int i = 1; x > 0; x /= i++) {
result.add(x % i);
}
Collections.reverse(result);
return result;
}
Of course, the indices array should be padded by 0's from the left so that length of the indices array is equal to number of elements to get the actual indices. Alternatively, the permutation could be applied from the right end.
Of course there is a need for bigints with such an interface
when you have n = 100 then you have n! permutations which means k is in the range k=<1,n!>
100!=93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
which does not fit into the standard unsigned int
2^32= 4294967296
2^64=18446744073709551616
see Fast exact bigint factorial
if you change the interface a bit you suddenly do not need any bigints anymore
just change API so it sequentially returns 1st,2nd,3th,...permutation without specifying k so you need something like:
Generalized Permutation (without repetitions) in C++
of course this is usable only if your usage of permutation is also sequential. You can also make function previous() to handle algorithms which are almost sequential. For random or non-sequential access you need to use bigints
First we can generate the factoradic reprsentation of k and then use it generate the necessary permutation. Please see https://en.wikipedia.org/wiki/Factorial_number_system for more details.
public String getPermutation(int n, int k) {
LinkedList<Integer> factoradic = new LinkedList<>();
k=k-1; // because factoradic representation and its mapping to permutation starts from 0
for(int i=1;i<=n; i++){ // get radix digits for n digits
factoradic.addFirst(k%i);
k=k/i;
}
//System.out.println(factoradic.size());
List<Integer> numbers = new LinkedList<>();
for(int i=1;i<=n;i++){
numbers.add(i);
}
StringBuilder str = new StringBuilder();
for(int x: factoradic){
// System.out.println(x);
str.append(String.valueOf(numbers.get(x)));
numbers.remove(x);
}
return str.toString();
}