Related
Coding Problem Link
i have coded the brute-force recursion without any DP.
public class coinChangeCombination {
public static void main(String[] args){
int[] coins = {2, 3, 5, 6};
int target = 7;
System.out.println(coinRecursive(0, target, coins, 0));
}
//basic recursion
public static int coinRecursive(int current, int target, int[] coins, int index){
if(current > target) return 0;
if(current == target) return 1;
int count = 0;
for(int i = index; i < coins.length; i++){
int res = coinRecursive(current+coins[i], target, coins, i);
count += res;
}
return count;
}
}
Now since two variables are getting changed in recursion, we will need a 2-d array to store the intermediate results but what does each cell of the 2-d array represent? Like in Fibonacci DP when we take a 1-d array, each cell represents the Fibonacci of that index, likewise what does our 2-d array in this question represent? i am unable to think the meaning behind it, whats the intuition?
A bottom-up approach for this coin changes problem in Java to demo the DP way:
class Solution {
public int change(int amount, int[] coins) {
int n = coins.length;
int[][] dp = new int[2][amount + 1];
for (int i = 0; i <= n; i++)
dp[i % 2][0] = 1; // one way to change 0 amount
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= amount; j++) {
dp[i % 2][j] = dp[(i - 1) % 2][j]; // skip ith coin
if (j >= coins[i - 1])
dp[i % 2][j] += dp[i % 2][j - coins[i - 1]]; // use ith coin
}
}
return dp[n % 2][amount];
}
}
I'm writing an algorithm that will return an array with determined length and number of inversions (number pairs, where the left side number is larger than the right side number). I.e. array [3, 1, 4, 2] contains three inversions (3, 1), (3, 2) and (4, 2). So in practice, when given the length of n=3 and number of inversions k=3, the algorithm should generate an array [3, 1, 4, 2] (or another array that fulfills these requirements).
Since the number of inversions is also the number of swaps that has to be made for the array to be sorted in ascending order, I approached this problem by creating an array from 1 to n - 1 and using an insertion sort algorithm in reverse to make k swaps.
This approach works just fine for smaller inputs, but the algorithm should be able to efficiently generate arrays up to n=10^6 and k=n(n-1)/2 and anything in between, so the algorithm should be working in O(n log n) time instead of O(n^2). Below is the code:
import java.util.*;
public class Inversions {
public int[] generate(int n, long k) {
// Don't mind these special cases
if (n == 1) {
int[] arr = {1};
return arr;
}
if (k == 0) {
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = 1;
}
return arr;
}
int[] arr = new int[n];
for (int i = 0; i < n; i++) {
arr[i] = i + 1;
}
int inversions = 0;
int i = 0;
while (inversions < k && i < n) {
int j = i - 1;
while (j >= 0 && arr[j] < arr[j + 1] && inversions < k) {
int helper = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = helper;
inversions++;
j--;
}
i++;
}
return arr;
}
}
And the main class for testing with different input arrays:
public class Main {
public static void main(String[] args) {
Inversions in = new Inversions();
int[] arr1 = in.generate(4,3);
int[] arr2 = in.generate(4,0);
int[] arr3 = in.generate(4,6);
System.out.println(Arrays.toString(arr1)); // [3,1,4,2]
System.out.println(Arrays.toString(arr2)); // [1,1,1,1]
System.out.println(Arrays.toString(arr3)); // [4,3,2,1]
}
}
The algorithm does not return exactly the same arrays as the sample results, but passes all the tests, except the ones where the input size is very large. I have also tried different variations with merge sort, since it's working in O(n log n time) but with no avail.
It would be great if you guys have some ideas. If you are not familiar with Java, doesn't matter, pseudocode or any other kinds of suggestions are more than welcome!
If you reverse the initial m elements in the array, you create m(m-1)/2 inversions.
If you reverse the initial m+1 elements, you create m(m+1)/2 inversions.
The difference between these is only m.
So:
Generate a sorted array
Find the largest m such that m(m-1)/2 <= k
Reverse the first m elements in the array to create m(m-1)/2 inversions
Shift the next element forward k - m(m-1)/2 positions to create the remaining required inversions.
This takes O(n) time, which is better than you require.
Another O(n) algorithm: Start with a sorted array. When you swap the first and last elements, you get x = 2 * (n-2) + 1 inversions. Consider these two elements fixed and work on the remaining array only. If x is too large, consider a smaller array. Repeat this as long as needed.
Untested code:
for (int first=0, last = n-1; remainingInversions>0; ) {
int x = 2 * (last-first-1) + 1;
if (x <= remainingInversion) {
first++;
last--;
remainingInversion -= x;
} else {
last--; // consider a smaller array
}
}
If k >= n - 1, put element n - 1 first in the array, so that it is inverted with n - 1 elements; otherwise put it last in the array, so that it is inverted with 0 elements. Continue this greedy approach to determine where the rest of the elements go.
Here's a solution that implements generate() to run in linear time with a little bit of math.
public class Inversions {
public static int[] generate(int n, long k) {
int[] array = new int[n];
// locate k in various sums of (n-1), (n-2), ..., 1
int a = (int) Math.sqrt((n * (n - 1) - 2 * k)); // between the sum of [(n-1)+...+(n-a)] and the sum of [(n-1)+...+(n-a-1)]
int b = n - 1 - a; // counts of (n-1), (n-2), ..., (n-a)
int c = (int) (k - n * b + (b * b + b) / 2); // spillover = k - [(n-1)+(n-b)]*b/2;
// put elements in the array
for (int i = 0; i < b; i++) {
array[i] = n - 1 - i;
}
for (int i = b; i < n - 1 - c; i++) {
array[i] = i - b;
}
array[n - 1 - c] = n - 1 - b;
for (int i = n - c; i < n; i++) {
array[i] = i - b - 1;
}
return array;
}
public static void main(String[] args) {
int n = Integer.parseInt(args[0]);
long k = Long.parseLong(args[1]);
for (int i = 0; i < n; i++) {
StdOut.print(generate(n, k)[i] + " ");
}
}
}
In fact, every time you exchange the last element with the one before it, the number of inversions increments. Here is a java solution:
public static int[] generate(int n, long k) {
int[] arr = new int[n];
for(int i = 0; i < n; i++) {
arr[i] = i;
}
long inversions = 0;
int j = (n-1);
int s = 0;
while(inversions < k) {
int temp = arr[j];
arr[j] = arr[j-1];
arr[j-1] = temp;
inversions++;
j--;
if(j == s) {
j = (n-1);
s++;
}
}
return arr;
}
I got an implementation in Python with O(n) complexity.
It is based on two rules.
Reversing an array of size m gives m*(m-1)/2 inversions.
Shifting an element by m positions, creates m inversions.
def get_m(k):
m=0
while m*(m-1)/2<=k:
m+=1
else:
m-=1
return m
def generate(l, k):
"""
Generate array of length l with k inversions.
"""
# Generate a sorted array of length l
arr = list(range(0,l))
# If no inversions are needed, return sorted array.
if k==0:
return arr
# Find largest m such that m*(m-1)/2 <= k
m=get_m(k)
# Reverse first m elements in the array which will give m*(m-1)/2 inversions
arr = arr[m-1::-1]+arr[m:]
# Calculate for any remaining inversions
remaining_k = k-(m*(m-1)/2)
# For remaining inversions, move the last element to its left by remaining_k
if remaining_k>0:
arr.insert(int(len(arr)-remaining_k - 1), arr[-1])
arr = arr[:-1]
return arr
if __name__ == '__main__':
l = int(sys.argv[1])
k = int(sys.argv[2])
arr = generate(l, k)
print(arr)
There's a very easy way to create n inversions...
That is to move the last element to the front.
It's not exactly efficient due to the additional memory used, but I would do something like this:
Create an array that is twice the length n.
Fill it from the start to the middle with a sentinel (i.e. null) if we use an Integer[] instead of int[].
Fill it from the middle, ascending.
Then do something like the below...
I'm sure I have off by one errors and other bugs but the general idea is captured in the below code.
int start = 0;
int mid = arr.length / 2;
int end = arr.length - 1;
while (v > 0)
{
if (v < (end - mid))
{
arr[start++] = arr[mid + v];
arr[mid + v] = null;
}
else
{
arr[start++] = arr[end];
v -= (end - mid);
end--;
}
}
So we have an array filled with the starting values, a bunch of nulls, then the original incremental values, with one that may have become null, and an "end" pointer that points to the middle of the original zone.
So the final step is to copy from 0 -> endPos, ignoring the nulls, to the final array.
The logic is not much difficult. For example, we have 10 numbers [0,1,2,3,4,5,6,7,8,9] say, to generate like 18 inversions. Firstly, insert 9 before 0, --->[9,0,1,2,3,4,5,6,7,8], which generates 9 inversions. Still 9 inversions left, so we insert 8 before 0, ---->[9,8,0,1,2,3,4,5,6,7], so we get additional 8 inversions. Finally, 1 inversions left, we insert 7 before 6----->[9,8,0,1,2,3,4,5,7,6]. I only use arrays in this case. This program works in O(n) complexity. The following code only considering n numbers (0,1,2.....n-1) and their inversions.
public static int[] generate(int n, long k) {
int[] a = new int[n];
int[] b = new int[n];
for (int i = 1; i < n; i++) {
a[i] = 1 + a[i - 1];
}
if (n == 0 || k == 0) return a;
else {
int i = 0;
while (k > 0) {
if (k > n - i - 1) {
b[i] = a[n - 1 - i];
}
else {
//auxilary array c to store value
int[] c = new int[(int) (k + 1)];
for (int j = i; j < n - 1 - k; j++) {
b[j] = j - i;
}
for (int j = (int) (n - 1 - k); j < n; j++) {
c[j - (int) (n - 1 - k)] = j - i;
}
b[(int) (n - 1 - k)] = c[(int) k];
for (int j = (int) (n - k); j < n; j++) {
b[j] = c[j - (int) (n - k)];
}
break;
}
k = k - (n - 1 - i);
i++;
}
return b;
}
}
#zhong yang: It works nicely in the expected range 0 <= k <= n(n-1)/2 but it should be better to throw either an exception or null if k is out of this range instead of returning some array!
I've implemented the Heap's algorithm for finding all permutations of the elements of array A:
//A = {1, 2, 3, 4}; B = perms(A) ; num_row(B) = (4!+1) and B[0][0] = 4!;
//This is B.R. Heap's algorithm
public static void perms(int [] A, int [][]B, int n)
{
if (n == 1)
{
int k = B[0][0];
for (int i = 0; i < A.length; i++)
{
B[k + 1][i] = A[i];
}
B[0][0]++;
}
else
{
for (int i = 0; i < n - 1 ;i++)
{
perms(A, B, n-1);
if (n % 2 == 0)
{
swap(A, i, n - 1);
}
else
{
swap(A, 0, n - 1);
}
}
perms(A, B, n - 1);
}
}
public static void swap(int[] A, int i, int j)
{
int temp = A[i];
A[i] = A[j];
A[j] = temp;
}
I'm new to Java. The problem is I want to have B as the output (return) of the function perms(A) , but in this implementation, I have to initialize a int[n! + 1][A.length] B array before calling the function. How can I do it?
Is there anything like private variable or anything in java to help a recursive function to remember a variable from a former call?
Thanks
You can create an "entering" method to recursion like this:
public static int[][] perms(int[] a){
int[][] perms = new int[factorial(a.length)+1][a.length];
perms(a,perms,a.length);
return perms;
}
Method factorial is well know method and can be found on Google for example
Wondering if n parameter is neccessary
EDIT
it is not neccessary (above corrected)
EDIT
By my test the k variable is just incrementing, so I would use static variable like this:
private static int counter = 0;
// your code here, following is a part of your perms method
if (n == 1)
{
for (int i = 0; i < A.length; i++)
{
B[counter][i] = A[i];
}
counter++;
}
//and my code corrected too:
public static int[][] perms(int[] a){
int[][] perms = new int[factorial(a.length)][a.length]; //+1 is not necessary
counter=0; //necessary to call it again
perms(a,perms,a.length);
return perms;
}
I have the following problem:
You are given N counters, initially set to 0, and you have two possible operations on them:
increase(X) − counter X is increased by 1,
max counter − all counters are set to the maximum value of any counter.
A non-empty zero-indexed array A of M integers is given. This array represents consecutive operations:
if A[K] = X, such that 1 ≤ X ≤ N, then operation K is increase(X),
if A[K] = N + 1 then operation K is max counter.
For example, given integer N = 5 and array A such that:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the values of the counters after each consecutive operation will be:
(0, 0, 1, 0, 0)
(0, 0, 1, 1, 0)
(0, 0, 1, 2, 0)
(2, 2, 2, 2, 2)
(3, 2, 2, 2, 2)
(3, 2, 2, 3, 2)
(3, 2, 2, 4, 2)
The goal is to calculate the value of every counter after all operations.
Write a function:
class Solution { public int[] solution(int N, int[] A); }
that, given an integer N and a non-empty zero-indexed array A consisting of M integers, returns a sequence of integers representing the values of the counters.
For example, given:
A[0] = 3
A[1] = 4
A[2] = 4
A[3] = 6
A[4] = 1
A[5] = 4
A[6] = 4
the function should return [3, 2, 2, 4, 2], as explained above.
Assume that:
N and M are integers within the range [1..100,000];
each element of array A is an integer within the range [1..N + 1].
Complexity:
expected worst-case time complexity is O(N+M);
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.
I have answered this problem using the following code, but only got 80% as opposed to 100% performance, despite having O(N+M) time complexity:
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int minimumValue = 0;
int lastMinimumValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > minimumValue){
minimumValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1 && lastMinimumValue!=minimumValue){
lastMinimumValue = minimumValue;
Arrays.fill(answer, minimumValue);
}
}
return answer;
}
}
Where is my performance here suffering? The code gives the right answer, but does not perform up-to-spec despite having the right time complexity.
Instead of calling Arrays.fill(answer, minimumValue); whenever you encounter a "max counter" operation, which takes O(N), you should keep track of the last max value that was assigned due to "max counter" operation, and update the entire array just one time, after all the operations are processed. This would take O(N+M).
I changed the variables names from min to max to make it less confusing.
public class Solution {
public int[] solution(int N, int[] A) {
int highestCounter = N;
int maxValue = 0;
int lastMaxValue = 0;
int [] answer = new int[N];
for (int i = 0; i < A.length; i++) {
int currentCounter = A[i];
int answerEquivalent = currentCounter -1;
if(currentCounter >0 && currentCounter<=highestCounter){
if (answer[answerEquivalent] < lastMaxValue)
answer[answerEquivalent] = lastMaxValue +1;
else
answer[answerEquivalent] = answer[answerEquivalent]+1;
if(answer[answerEquivalent] > maxValue){
maxValue = answer[answerEquivalent];
}
}
if (currentCounter == highestCounter +1){
lastMaxValue = maxValue;
}
}
// update all the counters smaller than lastMaxValue
for (int i = 0; i < answer.length; i++) {
if (answer[i] < lastMaxValue)
answer[i] = lastMaxValue;
}
return answer;
}
}
The following operation is O(n) time:
Arrays.fill(answer, minimumValue);
Now, if you are given a test case where the max counter operation is repeated often (say n/3 of the total operations) - you got yourself an O(n*m) algorithm (worst case analysis), and NOT O(n+m).
You can optimize it to be done in O(n+m) time, by using an algorithm that initializes an array in O(1) every time this operation happens.
This will reduce worst case time complexity from O(n*m) to O(n+m)1
(1)Theoretically, using the same idea, it can even be done in O(m) - regardless of the size of the number of counters, but the first allocation of the arrays takes O(n) time in java
This is a bit like #Eran's solution but encapsulates the functionality in an object. Essentially - keep track of a max value and an atLeast value and let the object's functionality do the rest.
private static class MaxCounter {
// Current set of values.
final int[] a;
// Keeps track of the current max value.
int currentMax = 0;
// Min value. If a[i] < atLeast the a[i] should appear as atLeast.
int atLeast = 0;
public MaxCounter(int n) {
this.a = new int[n];
}
// Perform the defined op.
public void op(int k) {
// Values are one-based.
k -= 1;
if (k < a.length) {
// Increment.
inc(k);
} else {
// Set max
max(k);
}
}
// Increment.
private void inc(int k) {
// Get new value.
int v = get(k) + 1;
// Keep track of current max.
if (v > currentMax) {
currentMax = v;
}
// Set new value.
a[k] = v;
}
private int get(int k) {
// Returns eithe a[k] or atLeast.
int v = a[k];
return v < atLeast ? atLeast : v;
}
private void max(int k) {
// Record new max.
atLeast = currentMax;
}
public int[] solution() {
// Give them the solution.
int[] solution = new int[a.length];
for (int i = 0; i < a.length; i++) {
solution[i] = get(i);
}
return solution;
}
#Override
public String toString() {
StringBuilder s = new StringBuilder("[");
for (int i = 0; i < a.length; i++) {
s.append(get(i));
if (i < a.length - 1) {
s.append(",");
}
}
return s.append("]").toString();
}
}
public void test() {
System.out.println("Hello");
int[] p = new int[]{3, 4, 4, 6, 1, 4, 4};
MaxCounter mc = new MaxCounter(5);
for (int i = 0; i < p.length; i++) {
mc.op(p[i]);
System.out.println(mc);
}
int[] mine = mc.solution();
System.out.println("Solution = " + Arrays.toString(mine));
}
My solution: 100\100
class Solution
{
public int maxCounterValue;
public int[] Counters;
public void Increase(int position)
{
position = position - 1;
Counters[position]++;
if (Counters[position] > maxCounterValue)
maxCounterValue = Counters[position];
}
public void SetMaxCounter()
{
for (int i = 0; i < Counters.Length; i++)
{
Counters[i] = maxCounterValue;
}
}
public int[] solution(int N, int[] A)
{
if (N < 1 || N > 100000) return null;
if (A.Length < 1) return null;
int nlusOne = N + 1;
Counters = new int[N];
int x;
for (int i = 0; i < A.Length; i++)
{
x = A[i];
if (x > 0 && x <= N)
{
Increase(x);
}
if (x == nlusOne && maxCounterValue > 0) // this used for all maxCounter values in array. Reduces addition loops
SetMaxCounter();
if (x > nlusOne)
return null;
}
return Counters;
}
}
( #molbdnilo : +1 !) As this is just an algorithm test, there's no sense getting too wordy about variables. "answerEquivalent" for a zero-based array index adjustment? Gimme a break ! Just answer[A[i] - 1] will do.
Test says to assume A values always lie between 1 and N+1. So checking for this is not needed.
fillArray(.) is an O(N) process which is within an O(M) process. This makes the whole code into an O(M*N) process when the max complexity desired is O(M+N).
The only way to achieve this is to only carry forward the current max value of the counters. This allows you to always save the correct max counter value when A[i] is N+1. The latter value is a sort of baseline value for all increments afterwards. After all A values are actioned, those counters which were never incremented via array entries can then be brought up to the all-counters baseline via a second for loop of complexity O(N).
Look at Eran's solution.
This is how we can eliminate O(N*M) complexity.
In this solutions, instead of populating result array for every A[K]=N+1, I tried to keep what is min value of all elements, and update result array once all operation has been completed.
If there is increase operation then updating that position :
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
And keep track of minVal for each element of result array.
Here is complete solution:
public int[] solution(int N, int[] A) {
int minVal = -1;
int maxCount = -1;
int[] counter = new int[N];
for (int i = 0; i < A.length; i++) {
int x = A[i];
if (x > 0 && x <= N) {
if (counter[x - 1] < minVal) {
counter[x - 1] = minVal + 1;
} else {
counter[x - 1]++;
}
if (maxCount < counter[x - 1]) {
maxCount = counter[x - 1];
}
}
if (x == N + 1 && maxCount > 0) {
minVal = maxCount;
}
}
for (int i = 0; i < counter.length; i++) {
if (counter[i] < minVal) {
counter[i] = minVal;
}
}
return counter;
}
This is my swift 3 solution (100/100)
public func solution(_ N : Int, _ A : inout [Int]) -> [Int] {
var counters = Array(repeating: 0, count: N)
var _max = 0
var _min = 0
for i in A {
if counters.count >= i {
let temp = max(counters[i-1] + 1, _min + 1)
_max = max(temp, _max)
counters[i-1] = temp
} else {
_min = _max
}
}
return counters.map { max($0, _min) }
}
I'm trying to recursively compute the fibonacci sequence to 100, store those returned values into an array using a the buildArray method, then print values stored in the array. I am getting a "cannot be resolved to a variable" compilation error when I try to print A[N] in the main method. I'm using longs because I'm computing the series up to 100, although I don't know if it's necessary to use longs.
If I substitute F(N) for A[N] the code works, but I need to put the values into an array and print that array. Does this code even store the values in an array? I'm just starting java, thanks.
public class MyFibonacci {
public static final int MAX = 100;
public static long[] buildArray(int MAX, int N) {
long[] A = new long[MAX];
A[0] = 0;
A[1] = 1;
for(N = 2; N < MAX; N++)
A[N] = F(N);
return A;
}
public static long F(int N) {
if(N == 0)
return 0;
if(N == 1)
return 1;
return F(N - 1) + F(N - 2);
}
public static void main(String[] args) {
for(int N = 0; N < MAX; N++)
System.out.println(N + " " + A[N]);
}
}
You have declared A[] within the scope of buildArray(int MAX, int N). As a result, A[] is not accessible outside of buildArray. You need to move your declaraction of long A[] to a class variable.
Additionally, you actually need to run buildArray for the array to be constructed.
For future reference, I highly recommend using proper tabbing structures. It makes it much easier to see what's happening. I've edited your code (though it will have to be approved) to include this.
Here's the code for what you need, I think:
public class MyFibonacci{
public static final int MAX = 100;
long[] A = new long[MAX];
public static long[] buildArray(int N){
A[0] = 0;
A[1] = 1;
for (N = 2; N < MAX; N++){
A[N] = F(N);
}
return A;
}
public static long F(int N)
{
if (N == 0) return 0;
if (N == 1) return 1;
return F(N-1) + F(N-2);
}
public static void main(String[] args)
{
buildArray(<some number - not sure where you get it from? N by the way in buildArray()>);
for (int N = 0; N < MAX; N++)
StdOut.println(N + " " + A[N]);
}
}
The main problem is that you're never calling the buildArray function.
To get your code to work, you only need to add this to main:
long[] A = buildArray(MAX, 0);
Some other things:
You can remove the parameter N and just declare it in the function (or remove it all-together, see below).
You already have access to MAX, no need to pass it to the function.
The for-loop in buildArray is rather inefficient, you can set up the array inside F.
Given the below, A as a class variable is cleaner than passing it around.
Finally, the code:
static int MAX = 100;
static long[] A;
public static void buildArray()
{
A = new long[MAX+1];
F(MAX);
}
public static long F(int N)
{
long val;
if (N < 2)
val = N;
else if (A[N] != 0) // HEY! It's already calculated! Awesome! Just return it.
return A[N];
else
val = F(N-1) + F(N-2);
A[N] = val;
return val;
}
public static void main(String[] args)
{
buildArray();
for (int N = 0; N <= MAX; N++)
System.out.println(N + " " + A[N]);
}
Since you can allocate array memory, it makes good sense to utilize it during calculation. Consider this method:
public static long[] f_a(int n) {
long[] a = new long[n];
a[1] = 1;
for (int i = 2; i < n; i++)
a[i] = a[i-1] + a[i-2];
return a;
}