Question :-
In the question we have to find the pivot index of the given array. And as per the given definition(given in the question) it is that point in the index such that if we calculate the sum of numbers on it's left and right they both comes out to be equal.
Example
Input: nums = [1,7,3,6,5,6]
Output: 3
Explanation:
The pivot index is 3.
Left sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11
Right sum = nums[4] + nums[5] = 5 + 6 = 11
My Approach and logic I tried
I calculate the total sum of array and then used a for loop to iterate from backwards in the array(from right to left) each time subtracting that element from total sum and comparing it to another loop which is calculating sum from right side such that when they get equal return that index element.
But I can't find the error
Code for the same
import java.util.*;
public class webs{
public static void main(String[] args){
int arr[] = {1, 7, 3, 6, 5, 6};
System.out.println(Calc(arr));
}
static int Calc(int arr[]){
int sum = 0;
int lsum = 0;
//this loop is for sum
for(int i =0; i < arr.length; i++){
sum += arr[i];
}
//this loop is for calculating sum from reverse
for(int j= arr.length - 1; j > 0; j--){
lsum += arr[j];
sum -= arr[j];
if(lsum == sum){
return arr[j];
}
else{
return -1;
}
}
return 0;
}
}
Please specify the error in this.
The for loop, in method Calc will only execute, at most, one iteration since it contains an if-else where both the if returns a value and the else returns a value. If you run your code with a debugger, you will discover that.
When I copied your code to my Eclipse, it warned me that the j-- part of the for loop is dead code. In other words it will never be executed because of the if-else statement in the loop body.
If lsum does not equal sum then you need to continue with the next loop iteration. Hence you need to remove the else.
Also, method Calc needs to return an index and not an element. Hence rather than
return arr[j];
you should
return j;
If the for loop terminates, that means that you did not find a pivot point and so the method should return -1 (negative one) and not zero. Hence the last line of method Calc should be
return -1;
Also, since you are iterating the array backwards, lsum should initially contain the sum of all the array elements and sum should be zero. In fact you either need to reverse sum and lsum or iterate the array forwards instead of backwards.
When iterating the array backwards, the terminating condition should be
j >= 0
and not
j > 0
because then you don't iterate the first element in the array.
Lastly, you need to adjust the value of sum after you test whether sum equals lsum.
Here is my rewrite of your code, containing the changes that I have described, above. I added print statements so you can [partially] see what is happening but as I said before, you need to learn how to debug your code.
static int Calc(int arr[]){
int sum = 0;
int lsum = 0;
//this loop is for sum
for(int i =0; i < arr.length; i++){
lsum += arr[i];
}
//this loop is for calculating sum from reverse
for(int j= arr.length - 1; j >= 0; j--){
lsum -= arr[j];
System.out.printf("%d. lsum = %d , sum = %d%n", j, lsum, sum);
if(lsum == sum){
System.out.println("Returning: " + j);
return j;
}
sum += arr[j];
}
System.out.println("Returning: -1");
return -1;
}
When I call method Calc with the sample array from your question, the following is printed:
5. lsum = 22 , sum = 0
4. lsum = 17 , sum = 6
3. lsum = 11 , sum = 11
Returning: 3
Related
I'm trying my hands on basic programming and I came across this question. I have a function with a return type as string, that takes an integer input and has to print the series mentioned. Here's what I did.
String s=new String("h");
int[] a=new int[n];
int k=1;
for(int i=0;i<n;i+=2)
{
a[i]=b;//line6
a[i+1]=n-(b-1);//line7
b++;
}
s=Arrays.toString(a);
return s;
When I enter an "even" no. like 4. I get the proper result [1,4,2,3].
But when I enter "odd" no. like 5. I get an ArrayOutOfBoundException
I Know where Im going wrong at line6 and line7 but I'm not getting an idea how to modify it accordingly.
I also wish to return the string as 1 n 2 n-1 3 n-2 ... instead of [1,n,2,n-1,3,n-2,..]
That's because you have a loop running from i = 0 to i < n, and you are trying to access a[i + 1]. This runs fine on even numbers because you're incrementing 2 each time, and the last iteration checks for a[n - 2] and a[n - 1].
The ArrayIndexOutOfBoundException occurs on odd numbers, however, because the last iteration attempts to access a[n - 1] and a[n].
One way to modify the loop would be to increment only by 1, and set the value of a[i] by checking the parity of i inside the loop:
for(int i = 0; i < n; i++, b++) {
a[i] = (i % 2 == 0)? b: (n - (b - 1));
}
consider the next approach:
for(int i=0;i<n/2;i++)
{
a[2*i] = i+1;
a[2*i+1] = n-i;
}
if (n&1==1) //how to check for oddity in Java?
a[n-1] = (n+1)/2
The inside of your loop should look like
a[i] = b;
if (i + 1 < n) { // check the bounds before writing at i+1
a[i + 1] = n - (b - 1);
}
b++;
The reason for that is that when having odd numbers (e.g. 5) i gets to become 4 in the last iteration of the loop, 4 is smaller than 5, therefore the code enters the loop, then you access a at index 4, which is okay, but then you try to access it at 4+1, which is 5, but the array does not have an index 5 because.
Split the problem up into two smaller problems:
Generating all values for even indices
for(int i = 0; i < a.length; i += 2)
a[i] = i + 1;
Generating all values for odd incides
for(int i = 1; i < a.length; i += 2)
a[i] = n - i / 2;
Thanks to integer-division i / 2 of an odd number can substitute (i - 1) / 2.
Full code
int[] a = new int[n];
for(int i = 0; i < a.length; i += 2)
a[i] = i + 1;
for(int i = 1; i < a.length; i += 2)
a[i] = n - i / 2;
return Arrays.toString(a);
I'm a beginner to java... if statements followed by else if statements are evaluated in order until one that evaluates to true is found, and I've seen many examples of this. But in this program, both statements (the if and the else if) are evaluated. Why?
public int centeredAverage(int[] nums) {
int[] nums = {1, 1, 5, 5, 10, 8, 7};
int sum = 0;
int centered = 0;
int min = nums[0];
int max = nums[0];
int i = 0;
for (i = 0; i < nums.length; i++){
if (nums[i] < min){
min = nums[i];
} else if (nums[i] > max){
max = nums[i];
}
sum += nums[i];
centered = ((sum-max-min)/(nums.length-2));
}
return centered;
}
Because they're in a loop that changes i and so changes nums[i] and so changes what if's are true.
Your passing in array of doubles by reference called nums and the defining an array of the same name in the method which seems odd. Also your start index for your for loop should be 1
Im guessing this is the same problem from codingbat, next time copy and paste the problem desciption for others!
public int centeredAverage(int[] nums) {
Arrays.sort(nums); //sorts the array smallest to biggest
int total = 0;
//nums is already sorted, so the smallest value is at spot 0
//and the biggest value is at the end.
for(int a = 1; a < nums.length - 1; a++){ //avoid the first and last numbers
total += nums[a];
}
return total / (nums.length - 2); //need ( ) so we can substract 2 first
//Another way could simply sum all the elements then subtract from that sum
//the biggest and smallest numbers in the array, then divide by nums.length- 2, it is a
//little more complex, but allows a for : each loop.
}
But for you, well since you are a beginner, restate your strategy (algorithm), find the smallest and biggest numbers in the array, subtract that out of the sum of all elements in the array then divide that number by nums.length - 2, since we are ignoring 2 numbers.
Working of If statement followed by else-if is fine here. We are getting expected result here. Both the statements if and else-if are not executed. Only that statement is executed which comes TRUE as per logic.
Here we can identify the working of the program using "System.out.println". Code and console output is given below...
int[] nums = {1, 1, 5, 5, 10, 8, 7};
int sum = 0;
int centered = 0;
int min = nums[0];
int max = nums[0];
int i = 0;
for (i = 0; i < nums.length; i++)
{
if (nums[i] > min)
{
min = nums[i];
System.out.println("inside first if: " + i);
// taking value of i in SOP to get the iteration value
}
else if (nums[i] > max)
{
max = nums[i];
}
sum += nums[i];
centered = ((sum-max-min)/(nums.length-2));
System.out.println("inside else if: " + i);
// taking value of i in SOP to get the iteration value
}
System.out.println("centered value "
+ " " + centered);
You can make a good usage of SOP in every program to get the execution order.
I'm reading Cormen's "Introduction to Algorithms".
For the linear algorithm for Max Sum Subarray problem I came up with my own solution. Didn't check existing one (Kadena's) before implementing.
Now I'm testing it with different test scenarios and always have better results than Kadena's. I don't believe in such a luck, but can't find what have I missed. Could you take a look whether it is a working solution?
public void findMaxSubarray(Number[] numbers) {
int maxSum = Integer.MIN_VALUE;
int left = 0;
int right = numbers.length - 1;
int i = 0;
int j = i + 1;
int sum = numbers[i].intValue();
while (i < numbers.length) {
if (maxSum < sum) {
maxSum = sum;
left = i;
right = j - 1;
}
if (j >= numbers.length)
return;
sum = sum + numbers[j].intValue();
if (sum <= 0) {
// ignoring "first" negative numbers. shift i to first non-negative
while (numbers[j].intValue() <= 0) {
if (maxSum < numbers[j].intValue()) {
maxSum = numbers[j].intValue();
left = j;
right = j;
}
if (++j >= numbers.length)
return;
}
i = ++j;
sum = 0;
}
j++;
}
System.out.println(String.format("Max subarray is %d, [%d; %d]", maxSum, left, right));
}
Update
The idea of code is to keep in track only one subarray, and adding to its' tail numbers, when numbers are that low that sum becomes negative - set beginning of array after the tail.
Additionally negative items in the beginning are being ignored. head of subarray is just shifted forward.
Everytime sum appears to be maximum - maxSum and limits are updated.
shift i() --to first non negative number
from j = i+1 up to N.length
sum + N[j]
if sum <= 0
i = j+1
if N[i] < 0
shift i()
sum = 0
I think your algorithm is basically sound, but it has two bugs that I can see:
On the input 1 -2 10 3, it will skip over the 10 and output 3. I think you can fix this by changing i = ++j; to i = j;.
In 2 different places you return if j goes past the end, which will cause no output to be produced at all! (This will happen if, e.g., a long list of negative numbers appears at the end of the list.)
Also I don't expect it to be faster (or slower, for that matter) than Kadane's. Summing two numbers is a fast operation, as fast as copying one variable to another, which is what you are doing when you shift the start of the subarray.
I'm coding a Bubble Selection method, which should work with these credentials:
/* Write code for a Bubble Sort algorithm that starts at the right side of
* of ArrayList of Comparable objects and "bubbles" the largest item to the
* left of the list. The result should be an ArrayList arranged in descending
* order.
*/
#SuppressWarnings("unchecked")
void bubbleSort(ArrayList <Comparable> list) {
int end = list.size();
for (int i = 0 ; i < end; i++){
for (int j = end; j > 0; j--){
if ( list.get(j).compareTo(list.get(j-1)) > 0 ){
//swap
Comparable temp = list.get(j);
list.set(j,list.get(j - 1));
list.set(j - 1, temp);
//System.out.println(list);
}
}
end--;
}
}
The problem is, Java will then tell me it is out of bounds.
If I instead use
for (int j = end - 1; j > 0; j--)
the code will then run, however it does not run the number of times it needs to run for the list to completely finish sorting (aka it stops one loop ahead)
As explained, you need to start in end-1, or else you'll be accessing out of bounds of the array.
Let's say you have an array of integers: 5 1 4
Your algorith will do this:
1st iteration -> i = 0 / j starting at 2
1 5 4
2nd iteration -> i = 1 / j starting at 1
It will now only compare 5 and 1 and not switching them, because 5 is higher. So, and the 4 and 5? They should be swapped. Your algorithm implementation is wrong.
If you remove the end--; it should work.
However, this can be optimized
Use this code it will work for your requirement in array implementation where size is your array length.
for (int i = 0; i < size - 1; j++) {
for (int j = i + 1; j < size - 1; k++){
if (array[i] > array[j]) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
}
If the array is long 3, array[3] is out of bound.
Since you start with array[lenght] you have to decrement it before entering in the for cycle like the code you provide.
Using end - 1 will compare last and second last values in list
if you use end it will try to compare last value and value at index after last which will give ArrayOutOfBound Exception.
Now For correct output you have to remove end--; line as per shown below
for (int i = 0 ; i < end; i++){
for (int j = end -1; j > 0; j--){
if ( list.get(j).compareTo(list.get(j-1)) > 0 ){
//swap
Comparable temp = list.get(j);
list.set(j,list.get(j - 1));
list.set(j - 1, temp);
}
}
//remove below line
end--;
}
This will short the list by one value from right side also. So removing This will work
I've been playing around a bit with the algorithms for getting the largest sum with no two adjacent elements in an array but I was thinking:
If we have an array with n elements and we want to find the largest sum so that 3 elements never touch. That's to say if we have the array a = [2, 5, 3, 7, 8, 1] we can pick 2 and 5 but not 2, 5 and 3 because then we have 3 in a row. The larget sum with these rules for this array would be: 22 (2 and 5, 7 and 8. 2+5+7+8=22)
I'm not sure how I would implement this, any ideas?
Edit:
I've only come so far as to think about what might be good to do:
Let's just stick to the same array:
int[] a = {2, 5, 3, 7, 8, 1};
int{} b = new int[n}; //an array to store results in
int n = a.length;
// base case
b[1] = a[1];
// go through each element:
for(int i = 1; i < n; i++)
{
/* find each possible way of going to the next element
use Math.max to take the "better" option to store in the array b*/
}
return b[n]; // return the last (biggest) element.
This is just a thought I got in my head, hasn't reached longer than this.
Algorithm for Maximum sum such that no two elements are adjacent:
Loop for all elements in arr[] and maintain two sums incl and excl where incl = Max sum including the previous element and excl = Max sum excluding the previous element.
Max sum excluding the current element will be max(incl, excl) and max sum including the current element will be excl + current element (Note that only excl is considered because elements cannot be adjacent).
At the end of the loop return max of incl and excl.
Implementation:
#include<stdio.h>
/*Function to return max sum such that no two elements
are adjacent */
int FindMaxSum(int arr[], int n)
{
int incl = arr[0];
int excl = 0;
int excl_new;
int i;
for (i = 1; i < n; i++)
{
/* current max excluding i */
excl_new = (incl > excl)? incl: excl;
/* current max including i */
incl = excl + arr[i];
excl = excl_new;
}
/* return max of incl and excl */
return ((incl > excl)? incl : excl);
}
/* Driver program to test above function */
int main()
{
int arr[] = {5, 5, 10, 100, 10, 5};
printf("%d \n", FindMaxSum(arr, 6));
getchar();
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
Edit 1:
If you understand the above code, we can easily do this problem by maintaining the count of already adjacent numbers for previous position.
Here is a working implementation to the required question
//We could assume we store optimal result upto i in array sum
//but we need only sum[i-3] to sum[i-1] to calculate sum[i]
//so in this code, I have instead maintained 3 ints
//So that space complexity to O(1) remains
#include<stdio.h>
int max(int a,int b)
{
if(a>b)
return 1;
else
return 0;
}
/*Function to return max sum such that no three elements
are adjacent */
int FindMaxSum(int arr[], int n)
{
int a1 = arr[0]+arr[1];//equivalent to sum[i-1]
int a2 =arr[0];//equivalent to sum[i-2]
int a3 = 0;//equivalent to sum [i-3]
int count=2;
int crr = 0;//current maximum, equivalent to sum[i]
int i;
int temp;
for (i = 2; i < n; i++)
{
if(count==2)//two elements were consecutive for sum[i-1]
{
temp=max(a2+arr[i],a1);
if(temp==1)
{
crr= a2+arr[i];
count = 1;
}
else
{
crr=a1;
count = 0;
}
//below is the case if we sould have rejected arr[i-2]
// to include arr[i-1],arr[i]
if(crr<(a3+arr[i-1]+arr[i]))
{
count=2;
crr=a3+arr[i-1]+arr[i];
}
}
else//case when we have count<2, obviously add the number
{
crr=a1+arr[i];
count++;
}
a3=a2;
a2=a1;
a1=crr;
}
return crr;
}
/* Driver program to test above function */
int main()
{
int arr[] = {2, 5, 3, 7, 8, 1};
printf("%d \n", FindMaxSum(arr, 6));
return 0;
}
Time Complexity: O(n)
Space Complexity: O(1)
adi's solution can be easily generalized to allow up to n adjacent elements to be included in the sum. The trick is to maintain an array of n + 1 elements, where the k-th element in the array (0 ≤ k ≤ n) gives the maximum sum assuming that the k previous inputs are included in the sum and the k+1-th isn't:
/**
* Find maximum sum of elements in the input array, with at most n adjacent
* elements included in the sum.
*/
public static int maxSum (int input[], int n) {
int sums[] = new int[n+1]; // new int[] fills the array with zeros
int max = 0;
for (int x: input) {
int newMax = max;
// update sums[k] for k > 0 by adding x to the old sums[k-1]
// (loop from top down to avoid overwriting sums[k-1] too soon)
for (int k = n; k > 0; k--) {
sums[k] = sums[k-1] + x;
if (sums[k] > newMax) newMax = sums[k];
}
sums[0] = max; // update sums[0] to best sum possible if x is excluded
max = newMax; // update maximum sum possible so far
}
return max;
}
Like adi's solution, this one also runs in linear time (to be exact, O(mn), where m is the length of the input and n is the maximum number of adjacent elements allowed in the sum) and uses a constant amount of memory independent of the input length (O(n)). In fact, it could even be easily modified to process input streams whose length is not known in advance.
I would imagine putting the array into a binary tree in that order. That way you can keep track of which element is next to each other. Then just simply do an if (node is not directly linked to each other) to sum the nodes which are not next to each other. You can potentially do it with recursion and return the maximum number, makes things easier to code. Hope it helps.
For a set with n entries, there are 2^n ways to partition it. So to generate all possible sets, just loop from 0:2^n-1 and pick the elements from the array with those entries set to 1 (bear with me; I'm getting to your question):
max = 0;
for (i = 0; i < 1<<n; ++i) {
sum = 0;
for (j = 0; j < n; ++j) {
if (i & (1<<j)) { sum += array[j]; }
}
if (sum > max) { /* store max and store i */ }
}
This will find the maximum way to sum the entries of an array. Now, the issue you want is that you don't want to allow all values of i - specifically those that contain 3 consecutive 1's. This can be done by testing if the number 7 (b111) is available at any bit-shift:
for (i = 0; i < 1<<n; ++i) {
for (j = 0; j < n-2; ++j) {
if ((i & (7 << j)) == (7 << j)) { /* skip this i */ }
}
...