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
I have an array of numbers say [1,2,3,1,1000] , now I want to get all possible combinations of this array and calculate its sum. Combinations are valid such that two combinations have different subset of elements. Then order all the sum values in descending order and get the top k elements.
Example:
[1,2,3,1,1000]
Combinations:
Duplicates of earlier ones are striked out, for example (3,1) matches the earlier (1,3).
(), (1), (2), (3), (1), (1000), (1,2), (1,3), (1,1), (1,1000), (2,3), (2,1), (2,1000), (3,1), (3,1000), (1,1000), (1,2,3), (1,2,1), (1,2,1000), (1,3,1), (1,3,1000), (1,1,1000), (2,3,1), (2,3,1000), (2,1,1000), (3,1,1000), (1,2,3,1), (1,2,3,1000), (1,2,1,1000), (1,3,1,1000), (2,3,1,1000), (1,2,3,1,1000)
And the corresponding sums:
0, 1, 2, 3, 1, 1000, 3, 4, 2, 1001, 5, 3, 1002, 4, 1003, 1001, 6, 4, 1003, 5, 1004, 1002, 6, 1005, 1003, 1004, 7, 1006, 1004, 1005, 1006, 1007
Getting top k=3, sums = 1007, 1006, 1005
So output is [1007, 1006, 1005].
Constraints:
Array size n = 1 to 105
Array elements -109 to 109
k ranges from 1 to 2000
This is my code, reference taken from here:
static List<Long> printDistSum(int arr[]) {
List<Long> list = new ArrayList<>();
int n = arr.length;
// There are totoal 2^n subsets
long total = (long) Math.pow(2, n);
// Consider all numbers from 0 to 2^n - 1
for (int i = 0; i < total; i++) {
long sum = 0;
// Consider binary representation of
// current i to decide which elements
// to pick.
for (int j = 0; j < n; j++)
if ((i & (1 << j)) != 0)
sum += arr[j];
// Print sum of picked elements.
list.add(sum);
}
return list;
}
This code works for small range of inputs but times out for large range of inputs. How to solve this program.
I probably have solution that should be good enough. It has time complexity O(n * k * log(k)).
First we need to calculate max sum - sum of all positive values.
Next we need to iterate over positive values, from smallest to largest. For each of these values we calculate sums of new combinations (at the start we have one combination with max sum).
New combinations will not contains given value so we need to substract it from sum.
At the end we need to iterate over negative values. These values are not belongs to combinations from previous step so we need to add these values to sums.
In every iteration are needed only k maximum sums. I used the PriorityQueue to store these sums. That class use heap data structure so adding/removing values has logarithmic time.
Code:
private static long[] findSums(int[] array, int k) {
long maxSum = Arrays.stream(array).filter(it -> it >= 0).sum();
int[] positives = Arrays.stream(array).filter(it -> it >= 0).sorted().toArray();
int[] negatives = Arrays.stream(array).filter(it -> it < 0).sorted().toArray();
// sort time complexity is O(n*log(n))
PriorityQueue<Long> sums = new PriorityQueue<>(k); // priority queue is implemented using heap so adding element has time complexity O(log(n))
sums.add(maxSum); // we start with max sum - combination of all positive elements
int previous = Integer.MIN_VALUE;
Long[] previousAddedSums = {};
Long[] sumsToIterate;
// iterate over positive values
for (int i = 0; i < positives.length; i++) {
if (positives[i] == previous) {
sumsToIterate = previousAddedSums;
} else {
sumsToIterate = sums.toArray(new Long[sums.size()]);
}
previousAddedSums = new Long[sumsToIterate.length];
for (int j = 0; j < sumsToIterate.length; j++) {
long newSum = sumsToIterate[j] - positives[i];
// new sum is calculated - value positives[i] is removed from combination (subtracted from sum of that combination)
sums.add(newSum);
previousAddedSums[j] = newSum;
if (sums.size() > k) {
sums.poll(); // only first k maximum sums are needed at the moment
}
}
previous = positives[i];
}
previous = Integer.MAX_VALUE;
// iterate over negative values in reverse order
for (int i = negatives.length - 1; i >= 0; i--) {
if (negatives[i] == previous) {
sumsToIterate = previousAddedSums;
} else {
sumsToIterate = sums.toArray(new Long[sums.size()]);
}
previousAddedSums = new Long[sumsToIterate.length];
for (int j = 0; j < sumsToIterate.length; j++) {
long newSum = sumsToIterate[j] + negatives[i]; // value negatives[i] is added to combination (added to sum of that combination)
sums.add(newSum);
previousAddedSums[j] = newSum;
if (sums.size() > k) {
sums.poll();
}
}
previous = negatives[i];
}
long[] result = new long[sums.size()];
for (int i = sums.size() - 1; i >=0 ; i--) {
result[i] = sums.poll();
}
// get sums from priority queue in proper order
return result;
// this whole method has time complexity O(n * k * log(k))
// k is less than or equal 2000 so it should be good enough ;)
}
Demo: https://ideone.com/yf6POI
Edit: I have fixed my solution. Instead of iterating over distinct values I check if current value is same like previous. In that case I use combinations (sums) created in previous step. This prevents from creating duplicates of combinations.
I'm sorry if I didn't explain this well enough. I don't have experience in describing algorithmic / mathematical things in english.
Pls ignore all previous posts cuz they are all wrong.
Intuitively, we gotta use backtrack to find all desired combos, but it's impossible to backtrack on 10^5 elements.
Constraint 1 <= n <= 10^5 alludes that our algorithm bottlenecked by O(nlogn) sorting
Constraint 1 <= k <= min(2000,2^n) alludes that we can backtrack on k elements since k is less than 11. 2^11=2024/log(2000)=11 -- actually this "2^n" gives away solution :)
My algorithm (nlog(n) + 2^k)
sort the array
Record the highest score combo which is the sum of all positive integers
Find a window in the sorted array of math.min(log(k)--which is less than 11,n) elements -- worst case, this window consists of the
lowest 11 absolute values in the sorted array. Several approaches to
achieve that, since the candidates must be inside 22 elements
window(11 smallest positive values + 11 biggest negative values), we
can use PriorityQueue of size 11 scanning over these 22 elements. or
we can use two pointers to find the sliding window of size 11.
backtrack on this 11 absolute value elements window, find sum of each combo and put them into a size k/k-1 PriorityQueue. (k is for
the case that there's no positive elements)
result is the sum of all positive integers plus (sum deducted by each of k-1 elements in PriorityQueue).
I was also asked the same question yesterday but sadly I was not able to solve it yesterday. I have tried solving it today and think I have the answer today.
First of all I don't think that different subsets mean different costs in a set i.e in array of [1,2,3,1] both subsets are valid => [1,2,3] and [2,3,1] as they both use different 1's. Now here is my solution keeping this in mind. But if you really want to keep distinct elements in set then you can simply remove the multiple elements and do partial_sort then.
Logic
Store sum of all +ve nos. in a variable, say maxsum.
Convert the negative nos. to their absolute values.
Get lowest min(k-1, n) elements in sorted order.
Find all their combinations and subtract them from the maxsum.
While finding all their combinations we only need lowest k-1 combos. So we have to find a way to keep the number of combinations to that. For that use a sorted data structure and limit its size to k and then for every element in the sorted array iterate through the combos and add those combos to the sorted data structure if the end element of that data structure is greater. Also pop the end element after that.
For taking care of the above point I am using 2 vectors since the order already remains sorted.
The proposed solution has time complexity of O(n*log(k) + k^2).
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int ll;
template <class T>
void print(vector<T> topSumm)
{
for (ll itr : topSumm)
cout << itr << '\t';
cout << '\n';
}
vector<ll> mergeSortedArrays(vector<ll> &minns, vector<ll> &temp)
{
vector<ll> ans(minns.size() + temp.size());
int i{0}, j{0}, k{0};
while (i < minns.size() && j < temp.size())
{
if (temp[j] < minns[i])
ans[k++] = temp[j++];
else
ans[k++] = minns[i++];
}
while (i < minns.size())
ans[k++] = minns[i++];
while (j < temp.size())
ans[k++] = temp[j++];
return ans;
}
vector<ll> topKSum(vector<int> &arr, int k)
{
int n{(int)arr.size()};
ll maxSumm{0};
for (int i{0}; i < n; ++i)
{
if (arr[i] > 0)
maxSumm += arr[i];
else
arr[i] = -arr[i];
}
int nk{min(k - 1, n)};
partial_sort(arr.begin(), arr.begin() + nk, arr.end());
vector<ll> minns{0, maxSumm};
ll summ{};
bool breakOuter{false};
for (int i{0}; i < nk; ++i)
{
vector<ll> temp;
for (ll nums : minns)
{
summ = nums + arr[i];
if (minns.size() + temp.size() < k)
temp.push_back(summ);
else
{
if (minns.back() > summ)
{
minns.pop_back();
temp.push_back(summ);
}
else
{
if (nums == 0)
breakOuter = true;
break;
}
}
}
if (breakOuter)
break;
minns = mergeSortedArrays(minns, temp);
}
vector<ll> ans(k);
int i{0};
for (ll nums : minns)
ans[i++] = maxSumm - nums;
return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
int n, k;
cin >> n >> k;
vector<int> arr(n);
ll maxSumm{0};
for (int i{0}; i < n; ++i)
cin >> arr[i];
vector<ll> topSums = topKSum(arr, k);
print<ll>(topSums);
}
return 0;
}
Here is my solution:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValues = 0;
int maxNum = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++){
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
int absValuesDiff = Math.min(absValues, maxNum);
return absValuesDiff;
}
I pass small test cases, but not ones with a larger data set.
As L_Cleo suggested, you indeed check the minimum value only once.
Instead, you should check it on every iteration of the loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
int absValue = Integer.MAX_VALUE;
Collections.sort(arr);
for (int i = 0; i < arr.size() - 1; i++) {
absValue = Math.min(absValue, Math.abs(arr.get(i) - arr.get(i + 1)));
}
return absValue;
}
I added the minimum check on every iteration. The checking is done between the absValue and the absolute difference of the current loop iteration.
By the end of the loop, absValue will contain the minimum value, because you have compared it to every other possibility.
The longer explanation why this works is this:
The reason why updating the absValue in each loop iteration is enough is this: absValue's first value is Integer.MAX_VALUE. This means that any other value will be smaller than absValue. In the first loop iteration, absValue is updated with the first absolute difference. In all other iterations, the code will always update absValue with the smaller value between the current absValue and the absolute difference you calculate on each iteration.
This guarantees that, for all iterations, the smallest value will be stored in absValue at some point, and in the further iterations, absValue value will not change.
The problem in your solution is that you're not checking all possible couples within the array of numbers.
With this for loop, for example:
for (int i = 0; i < arr.size() - 1; i++) {
absValues = Math.abs(arr.get(i) - arr.get(i + 1));
}
And iterating over the simple array 1, 4, 6, 7, you would be checking the couples [1,4], [4,6] and [6,7], but you're still missing 1,7 and 4,7.
So step number one would be to iterate over the array per every number of the array (knowing that the order of the pairs doesn't matter [1,6] == [6,1] in this case, you will have to check 1 less number every iteration of the outer loop... here is an example of a correct for loop:
public static int minimumAbsoluteDifference(List<Integer> arr) {
Collections.sort(arr);
int minAbsoluteValue = Integer.MAX_VALUE;
for(int i=0; i < arr.size() - 1; i++) {
for(int j=i+1; j < arr.size(); j++)
minAbsoluteValue = Math.min(Math.abs(arr.get(i) - arr.get(j)), minAbsoluteValue);
}
return minAbsoluteValue;
}
As you can see, another missing part in your solution is the tracking of the minimum value. You're checking the minimum value between the last iterated couple and the maxInteger value only once, while you have to that for every couple.
This might not be the most efficient solution...
int even = 0;
int odd = 0;
for(i=0;i<5;i++){
for(j=0;j<5;j++){
if(j%2>=i) // I think the problem is this
even += twoD[i][j];
else
if(i%2!>=j) // I think the problem is this
odd += twoD[j][i];
}
}
System.out.println("The sum of the even elements above the diagonal is: "+even);
System.out.println("The sum of the odd elements below the diagonal is: "+odd);
This is the code I am working with. The problem is it doesn't display the real sum of the elements above and below as I'd want in a diagonal. The matrix is basically randomized so I had to check it everytime to verify the sum.
For the elements above the diagonal j > i (index of column is always greater than that of the row); for the elements below j < i.
Then the loops may be optimized slightly to provide j > i and swapping indexes for elements below the matrix diagonal:
int even = 0;
int odd = 0;
for(int i=0; i<twoD.length; i++) {
for(int j=i + 1; j<twoD[i].length; j++) {
if(twoD[i][j] %2 == 0) {
even += twoD[i][j];
}
if(twoD[j][i] %2 != 0) { // swap indexes below diagonal
odd += twoD[j][i];
}
}
}
Exactly as you've thought, the conditions are incorrect. Actually I'm not sure what was the logic behind them.
What you need to do is to find whether given number is above or below diagonal. You can do that by comparing indicies themselves - j>i and j<i.
Only then you need to check if a given number (not index) is odd or even - twoD[i][j] % 2 == 0.
Something like so should get the job done:
for(i=0;i<5;i++){
for(j=0;j<5;j++){
if(j>i && twoD[i][j]%2==0){
even += twoD[i][j];
}
if(j<i && twoD[i][j]%2!=0){
odd += twoD[i][j];
}
}
}
I'm looking over an assignment that I finished a few days ago and realized I'm not supposed to use constants. The assignment is the well-known "find the largest sum of a sub-array of integers both positive and negative recursively using a divide and conquer approach" problem. My algorithm works, but a part of it uses a constant in order to figure out the largest sum of sub-arrays that include the middle of the array.
Here's the relevant code:
lfSum = Integer.MIN_VALUE;
sum = 0;
// Sum from left to mid
for (int i = mid; i >= LF; i--) {
sum += array[i];
if (sum > lfSum) {
lfSum = sum;
if (lfSum > lfMax) {
lfMax = lfSum;
}
}
}
rtSum = Integer.MIN_VALUE;
sum = 0;
// Sum from mid to right
for (int j = mid+1; j <= RT; j++) {
sum += array[j];
if (sum > rtSum) {
rtSum = sum;
if (rtSum > rtMax) {
rtMax = rtSum;
}
}
}
// Largest sum spanning whole array
midMax = lfSum + rtSum; // midMax = leftMid + midRight;
What this does is it loops through each half of the entire array and checks to see if the sum is larger than the smallest integer possible in case the entire array is negative. If it is, it sets that side's max sum to sum's value. If that value is larger than what one of the recursive calls returned (lfMax or rtMax), set the respective side's recursive value to it.
Like I said earlier, this works perfectly well, but I'm not supposed to be using "Integer.MIN_VALUE". Is there another way around this? Obviously I could initialize lfSum/rtSum to the numerical value of Integer.MIN_VALUE, but I'd like to know if there are any other options.
I've tried removing rtSum/lfSum and just comparing sum to the recursive values, and initializing lfSum/rtSum to 0, but both did not work correctly. Thanks for taking the time to read this!
You can initialize lfSum as null:
Integer lfSum = null;
And modify the if condition like this:
if (lfSum == null || (lfSum != null && sum > lfSum.intValue())) {
lfSum = sum;
if (lfSum > lfMax) {
lfMax = lfSum;
}
}
Similar strategy applies to rtSum.