Two player coin game : tracing optimal sequence in dynamic programming - java

Two players take turns choosing one of the outer coins. At the end we calculate the difference between the score two players get, given that they play optimally. for example the list{4,3,2,1},
the optimal sequence would be 4, 3, 2, 1. then i will get 4+2 = 6 scores and the opponent 4 scores.
Now i have developed an algorithm as follow:
My Job is to print the scores out, and also the optimal sequence in index. so in the array {4,3,2,1} the optimal sequence would be 0,1,2,3.
The maximum Runtime and Memory should not exceed n^2.
Therefore I implemented the above algorithm with bottom up approach,which means in an i*j table, according to my algorithm, subproblems are solved one by one until the only main problem, which locates at the top right corner(where i =0 and j = n-1). It works calculating the scores, but i have no idea how to trace the optimal sequence during runtime, since when I calculate subproblems by subproblems, only the score will be save and used in the next problem, while the sequence, which led to the final result, is hard to trace back.
I tried to create Pairs or multidimensional ArrayList to record the sequences and their corresponding memo[i][j]...... Well, they worked, but the memory needed would then be greater than n^2 and this is not allowed in my task.
So, does anymore have a better idea that does not require that much memory space?
Any help would be appreciated, cheers!
My code:
public int maxGain(int[] values) {
int n = values.length;
int [][] memo = new int[n][n];
for (int i = 0; i < n; i++)
memo[i][i] = values[i];
for (int i = 0, j = 1; j < n; i++, j++)
memo[i][j] = Math.max(values[i], values[j]);
for (int k = 2; k < n; k++) {
for (int i = 0, j = k; j < n; i++, j++) {
int a = values[i] + Math.min(memo[i + 2][j], memo[i + 1][j - 1]);
int b = values[j] + Math.min(memo[i + 1][j - 1], memo[i][j - 2]);
memo[i][j] = Math.max(a, b);
}
}
return memo[0][n - 1];
}

I guess your question is similar to Predict the Winner of LeetCode (486) with some minor changes that you would want to make:
Java
class Solution {
public boolean maxGain(int[] nums) {
int length = nums.length;
int[][] dp = new int[length][length];
for (int i = 0; i < length; i++)
dp[i][i] = nums[i];
for (int l = 1; l < length; l++)
for (int i = 0; i < length - l; i++) {
int j = i + l;
dp[i][j] = Math.max(nums[i] - dp[i + 1][j], nums[j] - dp[i][j - 1]);
}
return dp[0][length - 1] > -1;
}
}
Python
class Solution:
def max_gain(self, nums):
length = len(nums)
memo = [[-1 for _ in range(length)] for _ in range(length)]
#functools.lru_cache(None)
def f():
def helper(nums, i, j):
if i > j:
return 0
if i == j:
return nums[i]
if memo[i][j] != -1:
return memo[i][j]
cur = max(nums[i] + min(helper(nums, i + 2, j), helper(nums, i + 1, j - 1)),
nums[j] + min(helper(nums, i, j - 2), helper(nums, i + 1, j - 1)))
memo[i][j] = cur
return cur
score = helper(nums, 0, length - 1)
total = sum(nums)
return 2 * score >= total
return f()
O(N) Memory
The space complexity might be an order of N for the second solution provided in this link:
class Solution {
public boolean maxGain(int[] nums) {
if (nums == null)
return true;
int length = nums.length;
int[] dp = new int[length];
for (int i = length - 1; i >= 0; i--) {
for (int j = i; j < length; j++) {
if (i == j)
dp[i] = nums[i];
else
dp[j] = Math.max(nums[i] - dp[j], nums[j] - dp[j - 1]);
}
}
return dp[length - 1] > -1;
}
}
Reference
Most optimal solutions are here in the discussion board

Related

TapeEquilibrium, Solution Failing Two Edge Cases

Currently working on problems from codility for practice, and for some reason I'm unable to get more than 83% correctness overall, originally I solved it with 100% correctness but with N^2 time complexity (it needs to be N or lower)
I've adjusted my code to be able to solve in O(N) but now my correctness has dropped to 77%, I'm currently trying to solve for cases of 2 elements
ie) [1000,-1000] should return 2000, but I return a 0;
Link to Question on Codility:https://app.codility.com/programmers/lessons/3-time_complexity/tape_equilibrium/
The question:
A non-empty array A consisting of N integers is given. Array A represents numbers on a tape.
Any integer P, such that 0 < P < N, splits this tape into two non-empty parts: A[0], A[1], ..., A[P − 1] and A[P], A[P + 1], ..., A[N − 1].
The difference between the two parts is the value of: |(A[0] + A[1] + ... + A[P − 1]) − (A[P] + A[P + 1] + ... + A[N − 1])|
In other words, it is the absolute difference between the sum of the first part and the sum of the second part.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [2..100,000];
each element of array A is an integer within the range [−1,000..1,000]
class Solution {
public int solution(int[] A) {
// write your code in Java SE 8
int pval = Integer.MAX_VALUE;
int sum = 0;
int pone = 0;
int ptwo = 0;
int currdiff = 0;
for(int i = 0; i<A.length; i++ ){
sum += A[i];
}
ptwo = sum;
for(int j = 0; j< A.length; j++){
pone += A[j];
ptwo -= A[j];
currdiff = Math.abs(ptwo - pone);
if(currdiff < pval)
pval = currdiff;
}
return pval;
}
}
Any integer P, such that 0 < P < N, splits this tape into two non-empty parts
The "non-empty" is crucial here. If you would try printing both parts in the second loop you would see that in the last iteration the second part is empty.
All you need to do is skip the last iteration in you loop:
public int solution(int[] A) {
int pval = Integer.MAX_VALUE;
int sum = 0;
int pone = 0;
int ptwo = 0;
int currdiff = 0;
for(int i = 0; i<A.length; i++ ){
sum += A[i];
}
ptwo = sum;
for(int j = 0; j< A.length-1; j++){ //<- notice -1 here
pone += A[j];
ptwo -= A[j];
currdiff = Math.abs(ptwo - pone);
if(currdiff < pval)
pval = currdiff;
}
return pval;
}

How to calculate space and time complexity for this code

public static int desc(int number) {
// Time complexity = 2n+n2
// space complexity = ?
int i, j, temp;
int array[] = new int[Integer.toString(number).length()];
for (i = 0; i < array.length; i++)
array[i] = Integer.toString(number).charAt(i) - '0';
for (i = 0; i < array.length - 1; i++) {
for (j = 0; j < array.length - i - 1; j++) {
if (array[j] < array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
StringBuilder strNum = new StringBuilder();
for (int k : array) {
strNum.append(k);
}
int finalInt = Integer.parseInt(strNum.toString());
System.out.println(finalInt);
return finalInt;
}
This is my code as per my understanding I am able to calculate time complexity please suggest if the time complexity is correct or not and also help me to calculate the space complexity of this program I am bit confuse on how to calculate of space complexity .
First let's optimize your code from:
int array[] = new int[Integer.toString(number).length()];
for (i = 0; i < array.length; i++)
array[i] = Integer.toString(number).charAt(i) - '0';
to:
String to_number = Integer.toString(number);
int array[] = new int[to_number.length()];
for (i = 0; i < array.length; i++)
array[i] = to_number.charAt(i) - '0';
No need to call Integer.toString(number) multiple times.
Being N the number of digits in the parameter number (i.e., Integer.toString(number).length()) the time complexity can be calculated as follows:
String to_number = Integer.toString(number);
has a time complexity of N and the same for:
for (i = 0; i < array.length; i++)
array[i] = to_number.charAt(i) - '0';
The follow up double loop:
for (i = 0; i < array.length - 1; i++) {
for (j = 0; j < array.length - i - 1; j++) {
if (array[j] < array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
is a well-know for being N(N-1)/2, which can be simplified to a time complexity of O(N^2). The next loop
for (int k : array) {
strNum.append(k);
}
has time complexity of N. Finally,
int finalInt = Integer.parseInt(strNum.toString());
is also N. So the time complexity is N + N + N^2 + N + N, which simplifies to O(N^2) time complexity, also known as quadratic time complexity.
Now let us look at the space complexity:
int array[] = new int[Integer.toString(number).length()];
in this case N, and
for (int k : array) {
strNum.append(k);
}
also N, so the space complexity is 2N, which simplifies to O(N).

Improve Efficiency of Alog (Rotate Array to Left by n iterations)

I am solving a challenge to rotate array to left by n number of iterations.
Code is pretty much working but lags on very very huge input.
How to more improve efficiency
// Complete the rotLeft function below.
static int[] rotLeft(int[] a, int iterations) {
for(int i=0;i<iterations;i++)
{
int[] temp=Arrays.copyOfRange(a, 1, a.length);
temp=Arrays.copyOf(temp,a.length);
temp[a.length-1]=a[0];
a=temp;
}
return a;
}
Suggestions are welcome.
Thanks
Instead on shifting iterations you can calculate the final position directly.
finalIndex=(index-iterations+a.length) % a.length
+a.length is added to ensure that the finalIndex is always a not negattive value.
If you apply this to your algorithm, you get rid of the loop and do the whole thing in one step.
This reduced time complexity of the algorithm from O(a.length*iterations) to O(a.length).
There are few flaws in the code.
First, you do redundant work - if iterations > a.length - then after a.length iterations the array just returns back to itself.
Second, each iteration creates a whole new copy of the array!
Third, the new location of each element in the array can be predetermined by looking only on the array length, the number of iterations required, and the index of this element, no need to repeatidly go over iterations.
When taking these into considerations, this can boil down to something in the form of:
static int[] rotLeftEfficient(int[] a, int iterations) {
iterations = iterations % a.length;
int[] b = new int[a.length];
for (int i = 0; i < a.length; i++) {
int newIndex = (i - iterations + a.length) % a.length;
b[newIndex] = a[i];
}
return b;
}
This boils down to O(n) solution - where n is the number of elements in the array, with decent constants as well.
Here is a rotate in place (doesn't use a second array), with O(a.length) time complexity. On my system (Intel 3770K 3.5ghz), it can rotate a 2^28 = 268,435,456 element array in .17 (rotate 76) to .85 seconds (rotate 1). The swaps are done in sequential access sequences, which is cache friendly.
// rotate in place
public static void rolip(int[] a, int r){
r = r % a.length;
if(r == 0)
return;
int t;
int n = a.length - r;
int i = 0;
int j;
while(true){
if(r <= n){ // shift left r places
for(j = i+r; i < j; i++){
t = a[i]; // swap(a[i], a[i+r])
a[i] = a[i+r];
a[i+r] = t;
}
n -= r;
if(n == 0)
break;
} else { // shift right n places
i += r;
for(j = i+n; i < j; i++){
t = a[i]; // swap(a[i], a[i-n])
a[i] = a[i-n];
a[i-n] = t;
}
i -= n+r;
r -= n;
if(r == 0)
break;
}
}
}
Simple rotate using a second array. On my system (Intel 3770K 3.5ghz), it can rotate a 2^28 = 268,435,456 element array in .11 to .50 seconds.
public static void rol(int[] a, int r){
r = r % a.length;
if(r == 0)
return;
int n = a.length - r;
int i;
int j;
if(r <= n){ // if left rotate
int[] b = new int[r]; // save elements
for(j = 0; j < r; j++)
b[j] = a[j];
for(i = 0; i < n; i++) // shift elements
a[i] = a[j++];
for(j = 0; j < r; j++) // copy saved elements
a[i++] = b[j];
} else { // else right rotate
int[] b = new int[n]; // save elements
i = 0;
for(j = r; j < a.length; j++)
b[i++] = a[j];
i = j-1; // shift elements
for(j = i-n; j >= 0; j--)
a[i--] = a[j];
for(j = 0; j < n; j++) // copy saved elements
a[j] = b[j];
}
}
You don't need to do it for every iteration. Instead you can create a formula to figure out where every element would go.
For example, let's say that the size of your array is n.
Then, if you need to move your array to the left by 1 iteration, then an element at position p would be at (p + 1) % n position.
For i iterations, every element would be at (p + i) % n location. So, a loop for every iteration is not needed.
static int[] rotLeft(int[] a, int iterations) {
int[] answer = new int[a.length];
for(int i=0;i<a.length;i++)
{
answer[i] = a[(i - iterations + a.length) % (a.length)];
}
return answer;
}
What about this:
static int leftRotate(int arr[], int iterations,
int k)
{
/* To get the starting point of
rotated array */
int mod = k % iterations;
// Prints the rotated array from
// start position
for(int i = 0; i < iterations; ++i)
System.out.print(arr[(i + mod) % iterations]
+ " ");
System.out.println();
}
leftRotate(arr, iterations, arr.length);
Ref: https://www.geeksforgeeks.org/print-left-rotation-array/

Using a For Loop to Manually Sort an Array - Java

I'm having trouble manually sorting the array with a for loop. It works except for the first and last number. Here's my code:
Scanner numInput = new Scanner(System.in);
int tempVar, num;
String numbersString;
int[] numbers = {4, 11, 13, 12, 17, 35, 15, 7, 19, 3, 45};
for (int i = 0; i < numbers.length - 1; i++)
{
for(int j = 0; j < numbers.length - 1; j++)
{
if(numbers[i] < numbers[j + 1])
{
tempVar = numbers [j + 1];
numbers [j + 1]= numbers [i];
numbers [i] = tempVar;
}
}
}
numbersString = Arrays.toString(numbers);
System.out.println(numbersString);
You have to initialize the value for j as i+1, this sorting algorithm is called bubble sort, that works by repeatedly swapping the adjacent elements if they are in wrong order. The below method is always runs O(n^2) time even if the array is sorted.
public static void main (String[] args)
{
int[] array = {4,2,1,3,5,9,6,8,7};
for(int i = 0 ; i < array.length;i++)
{
for(int j = i+1 ; j< array.length;j++)
{
if(array[i] > array[j])
{
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
public int[] sort(int[] arr) {
int marker, i, temp;
marker =0;
i = 1;
while (marker < arr.length - 1) {
if (i == arr.length) {
marker++;
i = marker;
}
if (arr[marker] > arr[i]) {
temp = arr[marker];
arr[marker] = arr[i];
arr[i] = temp;
}
i++;
}
return arr;
}
Try this one:
int temp = 0;
for (int i = 0; i < numbers.length - 1; i++) {
for (int j = i + 1; j < numbers.length; j++) {
if (numbers[i] > numbers[j]) {
temp = numbers[j];
numbers[j] = numbers[i];
numbers[i] = temp;
}
}
}
You have little wrong second for iteration and reverse condition.
you have some errors in your code. I make some modifications, please look:
int tempVar, num;
String numbersString;
int[] numbers = {4, 11, 13, 12, 17, 35, 15, 7, 19, 3, 45};
for (int i = 0; i < numbers.length; i++) {
for (int j = i; j < numbers.length; j++) {
if (numbers[i] < numbers[j]) {
tempVar = numbers[i];
numbers[i] = numbers[j];
numbers[j] = tempVar;
}
}
}
numbersString = Arrays.toString(numbers);
System.out.println(numbersString);
First, I recommend you to iterate in the second loop, from i (beacause the items previous i are now sorted).
Second, you have to switch the items on i and j positions.
Finally, beacause you use < strict comparator un your loops break, you have to go user numbers.length and not numbers.length - 1 .
For more information, please see the buble sort algorithm
I will provide a modified version of your code with the intention of explaining why your code does not work.
First, we need to decide specifically what we want to do. Lets say we want to sort the numbers in descending order.
What does this mean? Every time when we are comparing two values at lowIndex and highIndex, we want to make sure that the value at lowIndex is higher than the value at highIndex.
The problem with your code is that it does not keep track of which index, i or j+1, that is lower.
When i==1 and j+1==2, your code will swap the values so that the greatest value out of numbers[1] and numbers[2] will be put at index 1.
When i==2 and j+1==1, your code will swap the values so that the smallest value out of numbers[1] and numbers[2] will be put at index 1.
This is incosistent. The algorithm is competing with itself, trying to move values in different directions. If we modify your code to check that we are consistent in whether we want to swap large values towards the beginning of the array or towards the end, your algorithm will start to work:
for (int i = 0; i < numbers.length - 1; i++)
{
for(int j = 0; j < numbers.length - 1; j++)
{
if(numbers[i] < numbers[j + 1] && i < (j + 1)) //NOTE: additional condition for indices
{
tempVar = numbers [j + 1];
numbers [j + 1]= numbers [i];
numbers [i] = tempVar;
}
}
}
Note, however, that the example above is just for explaining what goes wrong in execution of your code. Rather than using this code, it would probably be more appropriate to use one of the other answers to this question, or study and compare sorting algorithms on wikipedia
Try this
class desc
{
void printArray(int arr[], int n)
{
for (int i = 0; i < n; i++)
{
System.out.print(" "+arr[i]);
}
}
void sort(int arr[],int n)
{
for (int i = 1; i < n; i++)
{
if(arr[i] < arr[i - 1] )
{
arr[i] = arr[i] + arr[i - 1];
arr[i - 1] = arr[i] - arr[i - 1];
arr[i] = arr[i] - arr[i - 1];
i=0;
}
}
}
public static void main(String []args)throws Exception
{
int[] arr = {-5, 0, -7, -2, -5, 1, -9, -1};
int n = arr.length;
desc d=new desc();
d.sort(arr,n);
d.printArray(arr, n);
}
}
I believe what you are willing to do is selection sort? https://en.wikipedia.org/wiki/Selection_sort An other option I see is bubble sort but I'll try to explain selection sort.
So the first iteration of the outer for loop, the one with i, you check the whole array for the smallest number with the inner for loop, the one with j, and you put the smallest number upfront in the array. During the second iteration of the outer for loop you only go over the numbers you haven't checked yet, which is the second number through the last number. During the third iteration you go over the third number through the last number and so on. Here's how I adjusted your code, I adjusted the inner for loop so with each iteration you check a smaller sub-list and adjusted your if clause so that the smallest number is found:
int tempVar;
String numbersString;
int[] numbers = {4, 11, 13, 12, 17, 35, 15, 7, 19, 3, 45};
for (int i = 0; i < numbers.length - 1; i++)
{
// each iteration i you would need to go over a smaller array, so you set j = i each time
for(int j = i; j < numbers.length - 1; j++){
// checking if numbers[i] is greater than numbers[j + 1] instead of smaller than
if(numbers[i] > numbers[j + 1]){
tempVar = numbers [j + 1];
numbers [j + 1]= numbers [i];
numbers [i] = tempVar;
}
}
}
numbersString = Arrays.toString(numbers);
System.out.println(numbersString);
for(int i = 0; i < nums.length - 1; ++i){
for(int j = i + 1; j < nums.length; ++j){
if(nums[i]>nums[j]){
int tempVar = nums[i];
nums[i] = nums[j];
nums[j] = tempVar;
}
}
}
return nums;
}

Write a function which computes the perfect sums in an array?

Perfect sums is the sum of two or more number of elements of arrays whose sum is equal to a given number. Return 999 if not found.
my method signature is:
public static int persfectSum(int arr[], int input)
For example:
arr={2,3,5,6,8,10}
input = 10;
5+2+3= 10
2+8 = 10
So, the output is 2;
It is a variation of Subset-Sum problem - with an additional constraint on the size of the subset (larger then 1).
The problem is NP-Complete, but for relatively small integers can be solved using Dynamic Programming in pseudo-polynomial time.
A possibly simpler alternative which is feasible for small arrays is brute-force - just search all possible subsets, and verify for each if it matches the sum.
I believe these guidelines are more then enough as a starter for you to start programming the problem and solve your problem (HW?) on your own.
Good luck.
int PerfectSums(int n, int a[], int sum)
{
int dp[n + 1][sum + 1] ;
dp[0][0] = 1;
for (int i = 1; i <= sum; i++)
dp[0][i] = 0;
for (int i = 1; i <= n; i++)
dp[i][0] = 1;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= sum; j++)
{
if (a[i - 1] > j)
dp[i][j] = dp[i - 1][j];
else
{
dp[i][j] = dp[i - 1][j] + dp[i - 1][j - a[i - 1]];
}
}
}
return (dp[n][sum] == 0 ? 999 : dp[n][sum] ) ;
}

Categories

Resources