I want an efficient algorithm to find the next greater permutation of the given string.
Wikipedia has a nice article on lexicographical order generation. It also describes an algorithm to generate the next permutation.
Quoting:
The following algorithm generates the next permutation lexicographically after a given permutation. It changes the given permutation in-place.
Find the highest index i such that s[i] < s[i+1]. If no such index exists, the permutation is the last permutation.
Find the highest index j > i such that s[j] > s[i]. Such a j must exist, since i+1 is such an index.
Swap s[i] with s[j].
Reverse the order of all of the elements after index i till the last element.
A great solution that works is described here: https://www.nayuki.io/page/next-lexicographical-permutation-algorithm. And the solution that, if next permutation exists, returns it, otherwise returns false:
function nextPermutation(array) {
var i = array.length - 1;
while (i > 0 && array[i - 1] >= array[i]) {
i--;
}
if (i <= 0) {
return false;
}
var j = array.length - 1;
while (array[j] <= array[i - 1]) {
j--;
}
var temp = array[i - 1];
array[i - 1] = array[j];
array[j] = temp;
j = array.length - 1;
while (i < j) {
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
return array;
}
Using the source cited by #Fleischpfanzerl:
We follow the steps as below to find the next lexicographical permutation:
nums = [0,1,2,5,3,3,0]
nums = [0]*5
curr = nums[-1]
pivot = -1
for items in nums[-2::-1]:
if items >= curr:
pivot -= 1
curr = items
else:
break
if pivot == - len(nums):
print('break') # The input is already the last possible permutation
j = len(nums) - 1
while nums[j] <= nums[pivot - 1]:
j -= 1
nums[j], nums[pivot - 1] = nums[pivot - 1], nums[j]
nums[pivot:] = nums[pivot:][::-1]
> [1, 3, 0, 2, 3, 5]
So the idea is:
The idea is to follow steps -
Find a index 'pivot' from the end of the array such that nums[i - 1] < nums[i]
Find index j, such that nums[j] > nums[pivot - 1]
Swap both these indexes
Reverse the suffix starting at pivot
Homework? Anyway, can look at the C++ function std::next_permutation, or this:
http://blog.bjrn.se/2008/04/lexicographic-permutations-using.html
We can find the next largest lexicographic string for a given string S using the following step.
1. Iterate over every character, we will get the last value i (starting from the first character) that satisfies the given condition S[i] < S[i + 1]
2. Now, we will get the last value j such that S[i] < S[j]
3. We now interchange S[i] and S[j]. And for every character from i+1 till the end, we sort the characters. i.e., sort(S[i+1]..S[len(S) - 1])
The given string is the next largest lexicographic string of S. One can also use next_permutation function call in C++.
nextperm(a, n)
1. find an index j such that a[j….n - 1] forms a monotonically decreasing sequence.
2. If j == 0 next perm not possible
3. Else
1. Reverse the array a[j…n - 1]
2. Binary search for index of a[j - 1] in a[j….n - 1]
3. Let i be the returned index
4. Increment i until a[j - 1] < a[i]
5. Swap a[j - 1] and a[i]
O(n) for each permutation.
I came across a great tutorial.
link : https://www.youtube.com/watch?v=quAS1iydq7U
void Solution::nextPermutation(vector<int> &a) {
int k=0;
int n=a.size();
for(int i=0;i<n-1;i++)
{
if(a[i]<a[i+1])
{
k=i;
}
}
int ele=INT_MAX;
int pos=0;
for(int i=k+1;i<n;i++)
{
if(a[i]>a[k] && a[i]<ele)
{
ele=a[i];pos=i;
}
}
if(pos!=0)
{
swap(a[k],a[pos]);
reverse(a.begin()+k+1,a.end());
}
}
void Solution::nextPermutation(vector<int> &a) {
int i, j=-1, k, n=a.size();
for(i=0; i<n-1; i++) if(a[i] < a[i+1]) j=i;
if(j==-1) reverse(a.begin(), a.end());
else {
for(i=j+1; i<n; i++) if(a[j] < a[i]) k=i;
swap(a[j],a[k]);
reverse(a.begin()+j+1, a.end());
}}
A great solution that works is described here: https://www.nayuki.io/page/next-lexicographical-permutation-algorithm.
and if you are looking for
source code:
/**
* method to find the next lexicographical greater string
*
* #param w
* #return a new string
*/
static String biggerIsGreater(String w) {
char charArray[] = w.toCharArray();
int n = charArray.length;
int endIndex = 0;
// step-1) Start from the right most character and find the first character
// that is smaller than previous character.
for (endIndex = n - 1; endIndex > 0; endIndex--) {
if (charArray[endIndex] > charArray[endIndex - 1]) {
break;
}
}
// If no such char found, then all characters are in descending order
// means there cannot be a greater string with same set of characters
if (endIndex == 0) {
return "no answer";
} else {
int firstSmallChar = charArray[endIndex - 1], nextSmallChar = endIndex;
// step-2) Find the smallest character on right side of (endIndex - 1)'th
// character that is greater than charArray[endIndex - 1]
for (int startIndex = endIndex + 1; startIndex < n; startIndex++) {
if (charArray[startIndex] > firstSmallChar && charArray[startIndex] < charArray[nextSmallChar]) {
nextSmallChar = startIndex;
}
}
// step-3) Swap the above found next smallest character with charArray[endIndex - 1]
swap(charArray, endIndex - 1, nextSmallChar);
// step-4) Sort the charArray after (endIndex - 1)in ascending order
Arrays.sort(charArray, endIndex , n);
}
return new String(charArray);
}
/**
* method to swap ith character with jth character inside charArray
*
* #param charArray
* #param i
* #param j
*/
static void swap(char charArray[], int i, int j) {
char temp = charArray[i];
charArray[i] = charArray[j];
charArray[j] = temp;
}
If you are looking for video explanation for the same, you can visit here.
This problem can be solved just by using two simple algorithms searching and find smaller element in just O(1) extra space and O(nlogn ) time and also easy to implement .
To understand this approach clearly . Watch this Video : https://www.youtube.com/watch?v=DREZ9pb8EQI
def result(lst):
if len(lst) == 0:
return 0
if len(lst) == 1:
return [lst]
l = []
for i in range(len(lst)):
m = lst[i]
remLst = lst[:i] + lst[i+1:]
for p in result(remLst):
l.append([m] + p)
return l
result(['1', '2', '3'])
Start traversing from the end of the list. Compare each one with the previous index value.
If the previous index (say at index i-1) value, consider x, is lower than the current index (index i) value, sort the sublist on right side starting from current position i.
Pick one value from the current position till end which is just higher than x, and put it at index i-1. At the index the value was picked from, put x. That is:
swap(list[i-1], list[j]) where j >= i, and the list is sorted from index "i" onwards
Code:
public void nextPermutation(ArrayList<Integer> a) {
for (int i = a.size()-1; i > 0; i--){
if (a.get(i) > a.get(i-1)){
Collections.sort(a.subList(i, a.size()));
for (int j = i; j < a.size(); j++){
if (a.get(j) > a.get(i-1)) {
int replaceWith = a.get(j); // Just higher than ith element at right side.
a.set(j, a.get(i-1));
a.set(i-1, replaceWith);
return;
}
}
}
}
// It means the values are already in non-increasing order. i.e. Lexicographical highest
// So reset it back to lowest possible order by making it non-decreasing order.
for (int i = 0, j = a.size()-1; i < j; i++, j--){
int tmp = a.get(i);
a.set(i, a.get(j));
a.set(j, tmp);
}
}
Example :
10 40 30 20 => 20 10 30 40 // 20 is just bigger than 10
10 40 30 20 5 => 20 5 10 30 40 // 20 is just bigger than 10. Numbers on right side are just sorted form of this set {numberOnRightSide - justBigger + numberToBeReplaced}.
This is efficient enough up to strings with 11 letters.
// next_permutation example
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
void nextPerm(string word) {
vector<char> v(word.begin(), word.end());
vector<string> permvec; // permutation vector
string perm;
int counter = 0; //
int position = 0; // to find the position of keyword in the permutation vector
sort (v.begin(),v.end());
do {
perm = "";
for (vector<char>::const_iterator i = v.begin(); i != v.end(); ++i) {
perm += *i;
}
permvec.push_back(perm); // add permutation to vector
if (perm == word) {
position = counter +1;
}
counter++;
} while (next_permutation(v.begin(),v.end() ));
if (permvec.size() < 2 || word.length() < 2) {
cout << "No answer" << endl;
}
else if (position !=0) {
cout << "Answer: " << permvec.at(position) << endl;
}
}
int main () {
string word = "nextperm";
string key = "mreptxen";
nextPerm(word,key); // will check if the key is a permutation of the given word and return the next permutation after the key.
return 0;
}
I hope this code might be helpful.
int main() {
char str[100];
cin>>str;
int len=strlen(len);
int f=next_permutation(str,str+len);
if(f>0) {
print the string
} else {
cout<<"no answer";
}
}
Related
Dynamic Programming Change Problem (Limited Coins).
I'm trying to create a program that takes as INPUT:
int coinValues[]; //e.g [coin1,coin2,coin3]
int coinLimit[]; //e.g [2 coin1 available,1 coin2 available,...]
int amount; //the amount we want change for.
OUTPUT:
int DynProg[]; //of size amount+1.
And output should be an Array of size amount+1 of which each cell represents the optimal number of coins we need to give change for the amount of the cell's index.
EXAMPLE: Let's say that we have the cell of Array at index: 5 with a content of 2.
This means that in order to give change for the amount of 5(INDEX), you need 2(cell's content) coins (Optimal Solution).
Basically I need exactly the output of the first array of this video(C[p])
. It's exactly the same problem with the big DIFFERENCE of LIMITED COINS.
Link to Video.
Note: See the video to understand, ignore the 2nd array of the video, and have in mind that I don't need the combinations, but the DP array, so then I can find which coins to give as change.
Thank you.
Consider the next pseudocode:
for every coin nominal v = coinValues[i]:
loop coinLimit[i] times:
starting with k=0 entry, check for non-zero C[k]:
if C[k]+1 < C[k+v] then
replace C[k+v] with C[k]+1 and set S[k+v]=v
Is it clear?
O(nk) solution from an editorial I wrote a while ago:
We start with the basic DP solution that runs in O(k*sum(c)). We have our dp array, where dp[i][j] stores the least possible number of coins from the first i denominations that sum to j. We have the following transition: dp[i][j] = min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i].
To optimize this to an O(nk) solution, we can use a deque to memorize the minimum values from the previous iteration and make the transitions O(1). The basic idea is that if we want to find the minimum of the last m values in some array, we can maintain an increasing deque that stores possible candidates for the minimum. At each step, we pop off values at the end of the deque greater than the current value before pushing the current value into the back deque. Since the current value is both further to the right and less than the values we popped off, we can be sure they will never be the minimum. Then, we pop off the first element in the deque if it is more than m elements away. The minimum value at each step is now simply the first element in the deque.
We can apply a similar optimization trick to this problem. For each coin type i, we compute the elements of the dp array in this order: For each possible value of j % value[i] in increasing order, we process the values of j which when divided by value[i] produces that remainder in increasing order. Now we can apply the deque optimization trick to find min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i] in constant time.
Pseudocode:
let n = number of coin denominations
let k = amount of change needed
let v[i] = value of the ith denomination, 1 indexed
let c[i] = maximum number of coins of the ith denomination, 1 indexed
let dp[i][j] = the fewest number of coins needed to sum to j using the first i coin denominations
for i from 1 to k:
dp[0][i] = INF
for i from 1 to n:
for rem from 0 to v[i] - 1:
let d = empty double-ended-queue
for j from 0 to (k - rem) / v[i]:
let currval = rem + v[i] * j
if dp[i - 1][currval] is not INF:
while d is not empty and dp[i - 1][d.back() * v[i] + rem] + j - d.back() >= dp[i - 1][currval]:
d.pop_back()
d.push_back(j)
if d is not empty and j - d.front() > c[i]:
d.pop_front()
if d is empty:
dp[i][currval] = INF
else:
dp[i][currval] = dp[i - 1][d.front() * v[i] + rem] + j - d.front()
This is what you are looking for.
Assumptions made : Coin Values are in descending order
public class CoinChangeLimitedCoins {
public static void main(String[] args) {
int[] coins = { 5, 3, 2, 1 };
int[] counts = { 2, 1, 2, 1 };
int target = 9;
int[] nums = combine(coins, counts);
System.out.println(minCount(nums, target, 0, 0, 0));
}
private static int minCount(int[] nums, int target, int sum, int current, int count){
if(current > nums.length) return -1;
if(sum == target) return count;
if(sum + nums[current] <= target){
return minCount(nums, target, sum+nums[current], current+1, count+1);
} else {
return minCount(nums, target, sum, current+1, count);
}
}
private static int[] combine(int[] coins, int[] counts) {
int sum = 0;
for (int count : counts) {
sum += count;
}
int[] returnArray = new int[sum];
int returnArrayIndex = 0;
for (int i = 0; i < coins.length; i++) {
int count = counts[i];
while (count != 0) {
returnArray[returnArrayIndex] = coins[i];
returnArrayIndex++;
count--;
}
}
return returnArray;
}
}
You can check this question: Minimum coin change problem with limited amount of coins.
BTW, I created c++ program based above link's algorithm:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
void copyVec(vector<int> from, vector<int> &to){
for(vector<int>::size_type i = 0; i < from.size(); i++)
to[i] = from[i];
}
vector<int> makeChangeWithLimited(int amount, vector<int> coins, vector<int> limits)
{
vector<int> change;
vector<vector<int>> coinsUsed( amount + 1 , vector<int>(coins.size()));
vector<int> minCoins(amount+1,numeric_limits<int>::max() - 1);
minCoins[0] = 0;
vector<int> limitsCopy(limits.size());
copy(limits.begin(), limits.end(), limitsCopy.begin());
for (vector<int>::size_type i = 0; i < coins.size(); ++i)
{
while (limitsCopy[i] > 0)
{
for (int j = amount; j >= 0; --j)
{
int currAmount = j + coins[i];
if (currAmount <= amount)
{
if (minCoins[currAmount] > minCoins[j] + 1)
{
minCoins[currAmount] = minCoins[j] + 1;
copyVec(coinsUsed[j], coinsUsed[currAmount]);
coinsUsed[currAmount][i] += 1;
}
}
}
limitsCopy[i] -= 1;
}
}
if (minCoins[amount] == numeric_limits<int>::max() - 1)
{
return change;
}
copy(coinsUsed[amount].begin(),coinsUsed[amount].end(), back_inserter(change) );
return change;
}
int main()
{
vector<int> coins;
coins.push_back(20);
coins.push_back(50);
coins.push_back(100);
coins.push_back(200);
vector<int> limits;
limits.push_back(100);
limits.push_back(100);
limits.push_back(50);
limits.push_back(20);
int amount = 0;
cin >> amount;
while(amount){
vector<int> change = makeChangeWithLimited(amount,coins,limits);
for(vector<int>::size_type i = 0; i < change.size(); i++){
cout << change[i] << "x" << coins[i] << endl;
}
if(change.empty()){
cout << "IMPOSSIBE\n";
}
cin >> amount;
}
system("pause");
return 0;
}
Code in c#
private static int MinCoinsChangeWithLimitedCoins(int[] coins, int[] counts, int sum)
{
var dp = new int[sum + 1];
Array.Fill(dp, int.MaxValue);
dp[0] = 0;
for (int i = 0; i < coins.Length; i++) // n
{
int coin = coins[i];
for (int j = 0; j < counts[i]; j++) //
{
for (int s = sum; s >= coin ; s--) // sum
{
int remainder = s - coin;
if (remainder >= 0 && dp[remainder] != int.MaxValue)
{
dp[s] = Math.Min(1 + dp[remainder], dp[s]);
}
}
}
}
return dp[sum] == int.MaxValue ? -1 : dp[sum];
}
Given an unsorted array, find the max j - i difference between indices such that j > i and a[j] > a[i] in O(n). I am able to find j and i using trivial methods in O(n^2) complexity but would like to know how to do this in O(n)?
Input: {9, 2, 3, 4, 5, 6, 7, 8, 18, 0}
Output: 8 ( j = 8, i = 0)
Input: {1, 2, 3, 4, 5, 6}
Output: 5 (j = 5, i = 0)
For brevity's sake I am going to assume all the elements are unique. The algorithm can be extended to handle non-unique element case.
First, observe that if x and y are your desired max and min locations respectively, then there can not be any a[i] > a[x] and i > x, and similarly, no a[j] < a[y] and j < y.
So we scan along the array a and build an array S such that S[i] holds the index of the minimum element in a[0:i]. Similarly an array T which holds the index of the maximum element in a[n-1:i] (i.e., backwards).
Now we can see that a[S[i]] and a[T[i]] are necessarily decreasing sequences, since they were the minimum till i and maximum from n till i respectively.
So now we try to do a merge-sort like procedure. At each step, if a[S[head]] < a[T[head]], we pop off an element from T, otherwise we pop off an element from S. At each such step, we record the difference in the head of S and T if a[S[head]] < a[T[head]]. The maximum such difference gives you your answer.
EDIT: Here is a simple code in Python implementing the algorithm.
def getMaxDist(arr):
# get minima going forward
minimum = float("inf")
minima = collections.deque()
for i in range(len(arr)):
if arr[i] < minimum:
minimum = arr[i]
minima.append((arr[i], i))
# get maxima going back
maximum = float("-inf")
maxima = collections.deque()
for i in range(len(arr)-1,0,-1):
if arr[i] > maximum:
maximum = arr[i]
maxima.appendleft((arr[i], i))
# do merge between maxima and minima
maxdist = 0
while len(maxima) and len(minima):
if maxima[0][0] > minima[0][0]:
if maxima[0][1] - minima[0][1] > maxdist:
maxdist = maxima[0][1] - minima[0][1]
maxima.popleft()
else:
minima.popleft()
return maxdist
Let's make this simple observation: If we have 2 elements a[i], a[j] with i < j and a[i] < a[j] then we can be sure that j won't be part of the solution as the first element (he can be the second but that's a second story) because i would be a better alternative.
What this tells us is that if we build greedily a decreasing sequence from the elements of a the left part of the answer will surely come from there.
For example for : 12 3 61 23 51 2 the greedily decreasing sequence is built like this:
12 -> 12 3 -> we ignore 61 because it's worse than 3 -> we ignore 23 because it's worse than 3 -> we ignore 51 because it's worse than 3 -> 12 3 2.
So the answer would contain on the left side 12 3 or 2.
Now on a random case this has O(log N) length so you can binary search on it for each element as the right part of the answer and you would get O(N log log N) which is good, and if you apply the same logic on the right part of the string on a random case you could get O(log^2 N + N(from the reading)) which is O(N). But we can do O(N) on a non-random case too.
Suppose we have this decreasing sequence. We start from the right of the string and do the following while we can pair the last of the decreasing sequence with the current number
1) If we found a better solution by taking the last of the decreasing sequence and the current number than we update the answer
2) Even if we updated the answer or not we pop the last element of the decreasing sequence because we are it's perfect match (any other match would be to the left and would give an answer with smaller j - i)
3) Repeat while we can pair these 2
Example Code:
#include <iostream>
#include <vector>
using namespace std;
int main() {
int N; cin >> N;
vector<int> A(N + 1);
for (int i = 1; i <= N; ++i)
cin >> A[i];
// let's solve the problem
vector<int> decreasing;
pair<int, int> answer;
// build the decreasing sequence
decreasing.push_back(1);
for (int i = 1; i <= N; ++i)
if (A[i] < A[decreasing.back()])
decreasing.push_back(i); // we work with indexes because we might have equal values
for (int i = N; i > 0; --i) {
while (decreasing.size() and A[decreasing.back()] < A[i]) { // while we can pair these 2
pair<int, int> current_pair(decreasing.back(), i);
if (current_pair.second - current_pair.first > answer.second - answer.first)
answer = current_pair;
decreasing.pop_back();
}
}
cout << "Best pair found: (" << answer.first << ", " << answer.second << ") with values (" << A[answer.first] << ", " << A[answer.second] << ")\n";
}
Later Edit:
I see you gave an example: I indexed from 1 to make it clearer and I print (i, j) instead of (j, i). You can alter it as you see fit.
We can avoid checking the whole array by starting from the maximum difference of j-i and comparing arr[j]>arr[i] for all the possible combinations j and i for that particular maximum difference
Whenever we get a combination of (j,i) with arr[j]>arr[i] we can exit the loop
Example : In an array of {2,3,4,5,8,1}
first code will check for maximum difference 5(5-0) i.e (arr[0],arr[5]), if arr[5]>arr[0] function will exit else will take combinations of max diff 4 (5,1) and (4,0) i.e arr[5],arr[1] and arr[4],arr[0]
int maxIndexDiff(int arr[], int n)
{
int maxDiff = n-1;
int i, j;
while (maxDiff>0)
{
j=n-1;
while(j>=maxDiff)
{
i=j - maxDiff;
if(arr[j]>arr[i])
{
return maxDiff;
}
j=j-1;
}
maxDiff=maxDiff-1;
}
return -1;
}`
https://ide.geeksforgeeks.org/cjCW3wXjcj
Here is a very simple O(n) Python implementation of the merged down-sequence idea. The implementation works even in the case of duplicate values:
downs = [0]
for i in range(N):
if ar[i] < ar[downs[-1]]:
downs.append(i)
best = 0
i, j = len(downs)-1, N-1
while i >= 0:
if ar[downs[i]] <= ar[j]:
best = max(best, j-downs[i])
i -= 1
else:
j -= 1
print best
To solve this problem, we need to get two optimum indexes of arr[]: left index i and right index j. For an element arr[i], we do not need to consider arr[i] for left index if there is an element smaller than arr[i] on left side of arr[i]. Similarly, if there is a greater element on right side of arr[j] then we do not need to consider this j for right index. So we construct two auxiliary arrays LMin[] and RMax[] such that LMin[i] holds the smallest element on left side of arr[i] including arr[i], and RMax[j] holds the greatest element on right side of arr[j] including arr[j]. After constructing these two auxiliary arrays, we traverse both of these arrays from left to right. While traversing LMin[] and RMa[] if we see that LMin[i] is greater than RMax[j], then we must move ahead in LMin[] (or do i++) because all elements on left of LMin[i] are greater than or equal to LMin[i]. Otherwise we must move ahead in RMax[j] to look for a greater j – i value. Here is the c code running in O(n) time:
#include <stdio.h>
#include <stdlib.h>
/* Utility Functions to get max and minimum of two integers */
int max(int x, int y)
{
return x > y? x : y;
}
int min(int x, int y)
{
return x < y? x : y;
}
/* For a given array arr[], returns the maximum j – i such that
arr[j] > arr[i] */
int maxIndexDiff(int arr[], int n)
{
int maxDiff;
int i, j;
int *LMin = (int *)malloc(sizeof(int)*n);
int *RMax = (int *)malloc(sizeof(int)*n);
/* Construct LMin[] such that LMin[i] stores the minimum value
from (arr[0], arr[1], ... arr[i]) */
LMin[0] = arr[0];
for (i = 1; i < n; ++i)
LMin[i] = min(arr[i], LMin[i-1]);
/* Construct RMax[] such that RMax[j] stores the maximum value
from (arr[j], arr[j+1], ..arr[n-1]) */
RMax[n-1] = arr[n-1];
for (j = n-2; j >= 0; --j)
RMax[j] = max(arr[j], RMax[j+1]);
/* Traverse both arrays from left to right to find optimum j - i
This process is similar to merge() of MergeSort */
i = 0, j = 0, maxDiff = -1;
while (j < n && i < n)
{
if (LMin[i] < RMax[j])
{
maxDiff = max(maxDiff, j-i);
j = j + 1;
}
else
i = i+1;
}
return maxDiff;
}
/* Driver program to test above functions */
int main()
{
int arr[] = {1, 2, 3, 4, 5, 6};
int n = sizeof(arr)/sizeof(arr[0]);
int maxDiff = maxIndexDiff(arr, n);
printf("\n %d", maxDiff);
getchar();
return 0;
}
Simplified version of Subhasis Das answer using auxiliary arrays.
def maxdistance(nums):
n = len(nums)
minima ,maxima = [None]*n, [None]*n
minima[0],maxima[n-1] = nums[0],nums[n-1]
for i in range(1,n):
minima[i] = min(nums[i],minima[i-1])
for i in range(n-2,-1,-1):
maxima[i]= max(nums[i],maxima[i+1])
i,j,maxdist = 0,0,-1
while(i<n and j<n):
if minima[i] <maxima[j]:
maxdist = max(j-i,maxdist)
j = j+1
else:
i += 1
print maxdist
I can think of improvement over O(n^2), but need to verify if this is O(n) in worse case or not.
Create a variable BestSoln=0; and traverse the array for first element
and store the best solution for first element i.e bestSoln=k;.
Now for 2nd element consider only elements which are k distances away
from the second element.
If BestSoln in this case is better than first iteration then replace
it otherwise let it be like that. Keep iterating for other elements.
It can be improved further if we store max element for each subarray starting from i to end.
This can be done in O(n) by traversing the array from end.
If a particular element is more than it's local max then there is no need to do evaluation for this element.
Input:
{9, 2, 3, 4, 5, 6, 7, 8, 18, 0}
create local max array for this array:
[18,18,18,18,18,18,18,0,0] O(n).
Now, traverse the array for 9 ,here best solution will be i=0,j=8.
Now for second element or after it, we don't need to evaluate. and best solution is i=0,j=8.
But suppose array is Input:
{19, 2, 3, 4, 5, 6, 7, 8, 18, 0,4}
Local max array [18,18,18,18,18,18,18,0,0] then in first iteration we don't need to evaluate as local max is less than current elem.
Now for second iteration best solution is, i=1,j=10. Now for other elements we don't need to consider evaluation as they can't give best solution.
Let me know your view your use case to which my solution is not applicable.
This is a very simple solution for O(2n) of speed and additional ~O(2n) of space (in addition to the input array). The following implementation is in C:
int findMaxDiff(int array[], int size) {
int index = 0;
int maxima[size];
int indexes[size];
while (index < size) {
int max = array[index];
int i;
for (i = index; i < size; i++) {
if (array[i] > max) {
max = array[i];
indexes[index] = i;
}
}
maxima[index] = max;
index++;
}
int j;
int result;
for (j = 0; j < size; j++) {
int max2 = 0;
if (maxima[j] - array[j] > max2) {
max2 = maxima[j] - array[j];
result = indexes[j];
}
}
return result;
}
The first loop scan the array once, finding for each element the maximum of the remaining elements to its right. We store also the relative index in a separate array.
The second loops finds the maximum between each element and the correspondent right-hand-side maximum, and returns the right index.
My Solution with in O(log n) (Please correct me here if I am wrong in calculating this complexity)time ...
Idea is to insert into a BST and then search for node and if the node has a right child then traverse through the right sub tree to calculate the node with maximum index..
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int t1 = Integer.parseInt(br.readLine());
for(int j=0;j<t1;j++){
int size = Integer.parseInt(br.readLine());
String input = br.readLine();
String[] t = input.split(" ");
Node root = new Node(Integer.parseInt(t[0]),0);
for(int i=1;i<size;i++){
Node addNode = new Node(Integer.parseInt(t[i]),i);
insertIntoBST(root,addNode);
}
for(String s: t){
Node nd = findNode(root,Integer.parseInt(s));
if(nd.right != null){
int i = nd.index;
int j1 = calculate(nd.right);
mVal = max(mVal,j1-i);
}
}
System.out.println(mVal);
mVal=0;
}
}
static int mVal =0;
public static int calculate (Node root){
if(root==null){
return -1;
}
int i = max(calculate(root.left),calculate(root.right));
return max(root.index,i);
}
public static Node findNode(Node root,int n){
if(root==null){
return null;
}
if(root.value == n){
return root;
}
Node result = findNode(root.left,n);
if(result ==null){
result = findNode(root.right,n);
}
return result;
}
public static int max(int a , int b){
return a<b?b:a;
}
public static class Node{
Node left;
Node right;
int value;
int index;
public Node(int value,int index){
this.value = value;
this.index = index;
}
}
public static void insertIntoBST(Node root, Node addNode){
if(root.value< addNode.value){
if(root.right!=null){
insertIntoBST(root.right,addNode);
}else{
root.right = addNode;
}
}
if(root.value>=addNode.value){
if(root.left!=null){
insertIntoBST(root.left,addNode);
}else{
root.left =addNode;
}
}
}
}
A simplified algorithm from Subhasis Das's answer:
# assume list is not empty
max_dist = 0
acceptable_min = (0, arr[0])
acceptable_max = (0, arr[0])
min = (0, arr[0])
for i in range(len(arr)):
if arr[i] < min[1]:
min = (i, arr[i])
elif arr[i] - min[1] > max_dist:
max_dist = arr[i] - min[1]
acceptable_min = min
acceptable_max = (i, arr[i])
# acceptable_min[0] is the i
# acceptable_max[0] is the j
# max_dist is the max difference
Below is a C++ solution for the condition a[i] <= a[j]. It needs a slight modification to handle the case a[i] < a[j].
template<typename T>
std::size_t max_dist_sorted_pair(const std::vector<T>& seq)
{
const auto n = seq.size();
const auto less = [&seq](std::size_t i, std::size_t j)
{ return seq[i] < seq[j]; };
// max_right[i] is the position of the rightmost
// largest element in the suffix seq[i..]
std::vector<std::size_t> max_right(n);
max_right.back() = n - 1;
for (auto i = n - 1; i > 0; --i)
max_right[i - 1] = std::max(max_right[i], i - 1, less);
std::size_t max_dist = 0;
for (std::size_t i = 0, j = 0; i < n; ++i)
while (!less(max_right[j], i))
{
j = max_right[j];
max_dist = std::max(max_dist, j - i);
if (++j == n)
return max_dist;
}
return max_dist;
}
Please review this solution and cases where it might fail:
def maxIndexDiff(arr, n):
j = n-1
for i in range(0,n):
if j > i:
if arr[j] >= arr[i]:
return j-i
elif arr[j-1] >= arr[i]:
return (j-1) - i
elif arr[j] >= arr[i+1]:
return j - (i+1)
j -= 1
return -1
int maxIndexDiff(int arr[], int n)
{
// Your code here
vector<int> rightMax(n);
rightMax[n-1] = arr[n-1];
for(int i =n-2;i>=0;i--){
rightMax[i] = max(rightMax[i+1],arr[i]);
}
int i = 0,j=0,maxDis = 0;
while(i<n &&j<n){
if(rightMax[j]>=arr[i]){
maxDis = max(maxDis,j-i);
j++;
} else
i++;
}
return maxDis;
}
There is concept of keeping leftMin and rightMax but leftMin is not really required and leftMin will do the work anyways.
We are choosing rightMax and traversing from start till we get a smaller value than that!
Create Arraylist of pairs where is key is array element and value is the index. Sort this arraylist of pairs. Traverse this arraylist of pairs to get the maximum gap between(maxj-i). Also keep a track of maxj and update when new maxj is found. Please find my java solution which takes O(nlogn) time complexity and O(n) space complexity.
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
class MaxDistanceSolution {
private class Pair implements Comparable<Pair> {
int key;
int value;
public int getKey() {
return key;
}
public int getValue() {
return value;
}
Pair(int key, int value) {
this.key = key;
this.value = value;
}
#Override
public int compareTo(Pair o) {
return this.getKey() - o.getKey();
}
}
public int maximumGap(final ArrayList<Integer> A) {
int n = A.size();
ArrayList<Pair> B = new ArrayList<>();
for (int i = 0 ; i < n; i++)
B.add(new Pair(A.get(i), i));
Collections.sort(B);
int maxJ = B.get(n-1).getValue();
int gaps = 0;
for (int i = n - 2; i >= 0; i--) {
gaps = Math.max(gaps, maxJ - B.get(i).getValue());
maxJ = Math.max(maxJ, B.get(i).getValue());
}
return gaps;
}
}
public class MaxDistance {
public static void main(String[] args) {
MaxDistanceSolution sol = new MaxDistanceSolution();
ArrayList<Integer> A = new ArrayList<>(Arrays.asList(3, 5, 4, 2));
int gaps = sol.maximumGap(A);
System.out.println(gaps);
}
}
I have solved this question here.
https://github.com/nagendra547/coding-practice/blob/master/src/arrays/FindMaxIndexDifference.java
Putting code here too. Thanks.
private static int findMaxIndexDifferenceOptimal(int[] a) {
int n = a.length;
// array containing minimums
int A[] = new int[n];
A[0] = a[0];
for (int i = 1; i < n; i++) {
A[i] = Math.min(a[i], A[i - 1]);
}
// array containing maximums
int B[] = new int[n];
B[n - 1] = a[n - 1];
for (int j = n - 2; j >= 0; j--) {
B[j] = Math.max(a[j], B[j + 1]);
}
int i = 0, maxDiff = -1;
int j = 0;
while (i < n && j < n) {
if (B[j] > A[i]) {
maxDiff = Math.max(j - i, maxDiff);
j++;
} else {
i++;
}
}
return maxDiff;
}
Given an integer x and a sorted array a of N distinct integers, design a linear-time algorithm to determine if there exists two distinct indices i and j such that a[i] + a[j] == x
This is type of Subset sum problem
Here is my solution. I don't know if it was known earlier or not. Imagine 3D plot of function of two variables i and j:
sum(i,j) = a[i]+a[j]
For every i there is such j that a[i]+a[j] is closest to x. All these (i,j) pairs form closest-to-x line. We just need to walk along this line and look for a[i]+a[j] == x:
int i = 0;
int j = lower_bound(a.begin(), a.end(), x) - a.begin();
while (j >= 0 && j < a.size() && i < a.size()) {
int sum = a[i]+a[j];
if (sum == x) {
cout << "found: " << i << " " << j << endl;
return;
}
if (sum > x) j--;
else i++;
if (i > j) break;
}
cout << " not found\n";
Complexity: O(n)
think in terms of complements.
iterate over the list, figure out for each item what the number needed to get to X for that number is. stick number and complement into hash. while iterating check to see if number or its complement is in hash. if so, found.
edit: and as I have some time, some pseudo'ish code.
boolean find(int[] array, int x) {
HashSet<Integer> s = new HashSet<Integer>();
for(int i = 0; i < array.length; i++) {
if (s.contains(array[i]) || s.contains(x-array[i])) {
return true;
}
s.add(array[i]);
s.add(x-array[i]);
}
return false;
}
Given that the array is sorted (WLOG in descending order), we can do the following:
Algorithm A_1:
We are given (a_1,...,a_n,m), a_1<...,<a_n.
Put a pointer at the top of the list and one at the bottom.
Compute the sum where both pointers are.
If the sum is greater than m, move the above pointer down.
If the sum is less than m, move the lower pointer up.
If a pointer is on the other (here we assume each number can be employed only once), report unsat.
Otherwise, (an equivalent sum will be found), report sat.
It is clear that this is O(n) since the maximum number of sums computed is exactly n. The proof of correctness is left as an exercise.
This is merely a subroutine of the Horowitz and Sahni (1974) algorithm for SUBSET-SUM. (However, note that almost all general purpose SS algorithms contain such a routine, Schroeppel, Shamir (1981), Howgrave-Graham_Joux (2010), Becker-Joux (2011).)
If we were given an unordered list, implementing this algorithm would be O(nlogn) since we could sort the list using Mergesort, then apply A_1.
First pass search for the first value that is > ceil(x/2). Lets call this value L.
From index of L, search backwards till you find the other operand that matches the sum.
It is 2*n ~ O(n)
This we can extend to binary search.
Search for an element using binary search such that we find L, such that L is min(elements in a > ceil(x/2)).
Do the same for R, but now with L as the max size of searchable elements in the array.
This approach is 2*log(n).
Here's a python version using Dictionary data structure and number complement. This has linear running time(Order of N: O(N)):
def twoSum(N, x):
dict = {}
for i in range(len(N)):
complement = x - N[i]
if complement in dict:
return True
dict[N[i]] = i
return False
# Test
print twoSum([2, 7, 11, 15], 9) # True
print twoSum([2, 7, 11, 15], 3) # False
Iterate over the array and save the qualified numbers and their indices into the map. The time complexity of this algorithm is O(n).
vector<int> twoSum(vector<int> &numbers, int target) {
map<int, int> summap;
vector<int> result;
for (int i = 0; i < numbers.size(); i++) {
summap[numbers[i]] = i;
}
for (int i = 0; i < numbers.size(); i++) {
int searched = target - numbers[i];
if (summap.find(searched) != summap.end()) {
result.push_back(i + 1);
result.push_back(summap[searched] + 1);
break;
}
}
return result;
}
I would just add the difference to a HashSet<T> like this:
public static bool Find(int[] array, int toReach)
{
HashSet<int> hashSet = new HashSet<int>();
foreach (int current in array)
{
if (hashSet.Contains(current))
{
return true;
}
hashSet.Add(toReach - current);
}
return false;
}
Note: The code is mine but the test file was not. Also, this idea for the hash function comes from various readings on the net.
An implementation in Scala. It uses a hashMap and a custom (yet simple) mapping for the values. I agree that it does not makes use of the sorted nature of the initial array.
The hash function
I fix the bucket size by dividing each value by 10000. That number could vary, depending on the size you want for the buckets, which can be made optimal depending on the input range.
So for example, key 1 is responsible for all the integers from 1 to 9.
Impact on search scope
What that means, is that for a current value n, for which you're looking to find a complement c such as n + c = x (x being the element you're trying ton find a 2-SUM of), there is only 3 possibles buckets in which the complement can be:
-key
-key + 1
-key - 1
Let's say that your numbers are in a file of the following form:
0
1
10
10
-10
10000
-10000
10001
9999
-10001
-9999
10000
5000
5000
-5000
-1
1000
2000
-1000
-2000
Here's the implementation in Scala
import scala.collection.mutable
import scala.io.Source
object TwoSumRed {
val usage = """
Usage: scala TwoSumRed.scala [filename]
"""
def main(args: Array[String]) {
val carte = createMap(args) match {
case None => return
case Some(m) => m
}
var t: Int = 1
carte.foreach {
case (bucket, values) => {
var toCheck: Array[Long] = Array[Long]()
if (carte.contains(-bucket)) {
toCheck = toCheck ++: carte(-bucket)
}
if (carte.contains(-bucket - 1)) {
toCheck = toCheck ++: carte(-bucket - 1)
}
if (carte.contains(-bucket + 1)) {
toCheck = toCheck ++: carte(-bucket + 1)
}
values.foreach { v =>
toCheck.foreach { c =>
if ((c + v) == t) {
println(s"$c and $v forms a 2-sum for $t")
return
}
}
}
}
}
}
def createMap(args: Array[String]): Option[mutable.HashMap[Int, Array[Long]]] = {
var carte: mutable.HashMap[Int,Array[Long]] = mutable.HashMap[Int,Array[Long]]()
if (args.length == 1) {
val filename = args.toList(0)
val lines: List[Long] = Source.fromFile(filename).getLines().map(_.toLong).toList
lines.foreach { l =>
val idx: Int = math.floor(l / 10000).toInt
if (carte.contains(idx)) {
carte(idx) = carte(idx) :+ l
} else {
carte += (idx -> Array[Long](l))
}
}
Some(carte)
} else {
println(usage)
None
}
}
}
int[] b = new int[N];
for (int i = 0; i < N; i++)
{
b[i] = x - a[N -1 - i];
}
for (int i = 0, j = 0; i < N && j < N;)
if(a[i] == b[j])
{
cout << "found";
return;
} else if(a[i] < b[j])
i++;
else
j++;
cout << "not found";
Here is a linear time complexity solution O(n) time O(1) space
public void twoSum(int[] arr){
if(arr.length < 2) return;
int max = arr[0] + arr[1];
int bigger = Math.max(arr[0], arr[1]);
int smaller = Math.min(arr[0], arr[1]);
int biggerIndex = 0;
int smallerIndex = 0;
for(int i = 2 ; i < arr.length ; i++){
if(arr[i] + bigger <= max){ continue;}
else{
if(arr[i] > bigger){
smaller = bigger;
bigger = arr[i];
biggerIndex = i;
}else if(arr[i] > smaller)
{
smaller = arr[i];
smallerIndex = i;
}
max = bigger + smaller;
}
}
System.out.println("Biggest sum is: " + max + "with indices ["+biggerIndex+","+smallerIndex+"]");
}
Solution
We need array to store the indices
Check if the array is empty or contains less than 2 elements
Define the start and the end point of the array
Iterate till condition is met
Check if the sum is equal to the target. If yes get the indices.
If condition is not met then traverse left or right based on the sum value
Traverse to the right
Traverse to the left
For more info :[http://www.prathapkudupublog.com/2017/05/two-sum-ii-input-array-is-sorted.html
Credit to leonid
His solution in java, if you want to give it a shot
I removed the return, so if the array is sorted, but DOES allow duplicates, it still gives pairs
static boolean cpp(int[] a, int x) {
int i = 0;
int j = a.length - 1;
while (j >= 0 && j < a.length && i < a.length) {
int sum = a[i] + a[j];
if (sum == x) {
System.out.printf("found %s, %s \n", i, j);
// return true;
}
if (sum > x) j--;
else i++;
if (i > j) break;
}
System.out.println("not found");
return false;
}
The classic linear time two-pointer solution does not require hashing so can solve related problems such as approximate sum (find closest pair sum to target).
First, a simple n log n solution: walk through array elements a[i], and use binary search to find the best a[j].
To get rid of the log factor, use the following observation: as the list is sorted, iterating through indices i gives a[i] is increasing, so any corresponding a[j] is decreasing in value and in index j. This gives the two-pointer solution: start with indices lo = 0, hi = N-1 (pointing to a[0] and a[N-1]). For a[0], find the best a[hi] by decreasing hi. Then increment lo and for each a[lo], decrease hi until a[lo] + a[hi] is the best. The algorithm can stop when it reaches lo == hi.
An array contains both positive and negative elements, find the maximum subarray whose sum equals 0.
The link in the current accepted answer requires to sign up for a membership and I do not its content.
This algorithm will find all subarrays with sum 0 and it can be easily modified to find the minimal one or to keep track of the start and end indexes. This algorithm is O(n).
Given an int[] input array, you can create an int[] tmp array where tmp[i] = tmp[i - 1] + input[i]; Each element of tmp will store the sum of the input up to that element(prefix sum of array).
Now if you check tmp, you'll notice that there might be values that are equal to each other. Let's say that this values are at indexes j an k with j < k, then the sum of the input till j is equal to the sum till k and this means that the sum of the portion of the array between j and k is 0! Specifically the 0 sum subarray will be from index j + 1 to k.
NOTE: if j + 1 == k, then k is 0 and that's it! ;)
NOTE: The algorithm should consider a virtual tmp[-1] = 0;
NOTE: An empty array has sum 0 and it's minimal and this special case should be brought up as well in an interview. Then the interviewer will say that doesn't count but that's another problem! ;)
The implementation can be done in different ways including using a HashMap with pairs but be careful with the special case in the NOTE section above.
Example:
int[] input = {4, 6, 3, -9, -5, 1, 3, 0, 2}
int[] tmp = {4, 10, 13, 4, -1, 0, 3, 3, 5}
Value 4 in tmp at index 0 and 3 ==> sum tmp 1 to 3 = 0, length (3 - 1) + 1 = 3
Value 0 in tmp at index 5 ==> sum tmp 0 to 5 = 0, length (5 - 0) + 1 = 6
Value 3 in tmp at index 6 and 7 ==> sum tmp 7 to 7 = 0, length (7 - 7) + 1 = 1
****UPDATE****
Assuming that in our tmp array we end up with multiple element with the same value then you have to consider every identical pair in it! Example (keep in mind the virtual '0' at index '-1'):
int[] array = {0, 1, -1, 0}
int[] tmp = {0, 1, 0, 0}
By applying the same algorithm described above the 0-sum subarrays are delimited by the following indexes (included):
[0] [0-2] [0-3] [1-2] [1-3] [3]
Although the presence of multiple entries with the same value might impact the complexity of the algorithm depending on the implementation, I believe that by using an inverted index on tmp (mapping a value to the indexes where it appears) we can keep the running time at O(n).
This is one the same lines as suggested by Gevorg but I have used a hash map for quick lookup. O(n) complexity used extra space though.
private static void subArraySumsZero()
{
int [] seed = new int[] {1,2,3,4,-9,6,7,-8,1,9};
int currSum = 0;
HashMap<Integer, Integer> sumMap = new HashMap<Integer, Integer>();
for(int i = 0 ; i < seed.length ; i ++)
{
currSum += seed[i];
if(currSum == 0)
{
System.out.println("subset : { 0 - " + i + " }");
}
else if(sumMap.get(currSum) != null)
{
System.out.println("subset : { "
+ (sumMap.get(currSum) + 1)
+ " - " + i + " }");
sumMap.put(currSum, i);
}
else
sumMap.put(currSum, i);
}
System.out.println("HASH MAP HAS: " + sumMap);
}
The output generated has index of elements (zero based):
subset : { 1 - 4 }
subset : { 3 - 7 }
subset : { 6 - 8 }
1. Given A[i]
A[i] | 2 | 1 | -1 | 0 | 2 | -1 | -1
-------+---|----|--------|---|----|---
sum[i] | 2 | 3 | 2 | 2 | 4 | 3 | 2
2. sum[i] = A[0] + A[1] + ...+ A[i]
3. build a map<Integer, Set>
4. loop through array sum, and lookup map to get the set and generate set, and push <sum[i], i> into map.
Complexity O(n)
Here's my implementation, it's the obvious approach so it's probably sub-optimized, but at least its clear. Please correct me if i'm wrong.
Starts from each index of the array and calculates and compares the individual sums (tempsum) with the desired sum (in this case, sum = 0). Since the integers are signed, we must calculate every possible combination.
If you don't need the full list of sub-arrays, you can always put conditions in the inner loop to break out of it. (Say you just want to know if such a sub-array exists, just return true when tempsum = sum).
public static string[] SubArraySumList(int[] array, int sum)
{
int tempsum;
List<string> list = new List<string>();
for (int i = 0; i < array.Length; i++)
{
tempsum = 0;
for (int j = i; j < array.Length; j++)
{
tempsum += array[j];
if (tempsum == sum)
{
list.Add(String.Format("[{0}-{1}]", i, j));
}
}
}
return list.ToArray();
}
Calling the function:
int[] array = SubArraySumList(new int { 0, -1, 1, 0 }, 0));
Printing the contents of the output array:
[0-0], [0-2], [0-3], [1-2], [1-3], [3-3]
Following solution finds max length subarray with a given sum k without using dynamic programming, but using simple rescursion. Here i_s is start index and i_e is end index for the current value of sum
##Input the array and sum to be found(0 in your case)
a = map(int,raw_input().split())
k = int(raw_input())
##initialize total sum=0
totalsum=0
##Recursive function to find max len 0
def findMaxLen(sumL,i_s,i_e):
if i_s<len(a)-1 and i_e>0:
if sumL==k:
print i_s, i_e
return (i_s,i_e)
else:
x = findMaxLen(sumL-a[i_s],i_s+1,i_e)
y = findMaxLen(sumL-a[i_e],i_s,i_e-1)
if x[1]-x[0]>y[1]-y[0]:
return x
else:
return y
else:
##Result not there
return (-1,-1)
## find total sum
for i in range(len(a)):
totalsum += a[i]
##if totalsum==0, max array is array itself
if totalsum == k:
print "seq found at",0,len(a)-1
##else use recursion
else:
print findMaxLen(totalsum,0,len(a)-1)
Time complexity is O(n) and space complexity is O(n) due to recursive memory stack
Here's an O(n) implementation in java
The idea is to iterate through the given array and for every element arr[i], calculate sum of elements form 0 to i, store each sum in HashMap.
If an element is 0, it's considerd as a a ZeroSum sub array.
if sum became 0, then there is a ZeroSum sub array, from 0 to i.
If the current sum has been seen before in HashMap, then there is a ZeroSum sub array, from that point to i.
Code:
import java.util.*;
import java.lang.*;
class Rextester
{
private static final int[] EMPTY = {};
// Returns int[] if arr[] has a subarray with sero sum
static int[] findZeroSumSubarray(int arr[])
{
if (arr.length == 0) return EMPTY;
// Creates an empty hashMap hM
HashMap<Integer, Integer> hM = new HashMap<Integer, Integer>();
// Initialize sum of elements
int sum = 0;
for (int i = 0; i < arr.length; i++)
{
sum += arr[i];
if (arr[i] == 0) //Current element is 0
{
return new int[]{0};
}
else if (sum == 0) // sum of elements from 0 to i is 0
{
return Arrays.copyOfRange(arr, 0, i+1);
}
else if (hM.get(sum) != null) // sum is already present in hash map
{
return Arrays.copyOfRange(arr, hM.get(sum)+1, i+1);
}
else
{
// Add sum to hash map
hM.put(sum, i);
}
}
// We reach here only when there is no subarray with 0 sum
return null;
}
public static void main(String arg[])
{
//int arr[] = {};
int arr[] = { 2, -3, 1, 4, 6}; //Case left
//int arr[] = { 0, 2, -3, 1, 4, 6}; //Case 0
//int arr[] = { 4, 2, -3, 1, 4}; // Case middle
int result[] = findZeroSumSubarray(arr);
if (result == EMPTY){
System.out.println("An empty array is ZeroSum, LOL");
}
else if ( result != null){
System.out.println("Found a subarray with 0 sum :" );
for (int i: result) System.out.println(i);
}
else
System.out.println("No Subarray with 0 sum");
}
}
Please see the experiment here: http://rextester.com/PAKT41271
An array contains positive and negative numbers. Find the sub-array that has the maximum sum
public static int findMaxSubArray(int[] array)
{
int max=0,cumulativeSum=0,i=0,start=0,end=0,savepoint=0;
while(i<array.length)
{
if(cumulativeSum+array[i]<0)
{
cumulativeSum=0;
savepoint=start;
start=i+1;
}
else
cumulativeSum=cumulativeSum+array[i];
if(cumulativeSum>max)
{
max=cumulativeSum;
savepoint=start;
end=i;
}
i++;
}
System.out.println("Max : "+max+" Start indices : "+savepoint+" end indices : "+end);
return max;
}
Below codes can find out every possible sub-array that has a sum being a given number, and (of course) it can find out the shortest and longest sub-array of that kind.
public static void findGivenSumSubarray(int arr[], int givenSum) {
int sum = 0;
int sStart = 0, sEnd = Integer.MAX_VALUE - 1; // Start & end position of the shortest sub-array
int lStart = Integer.MAX_VALUE - 1, lEnd = 0; // Start & end position of the longest sub-array
HashMap<Integer, ArrayList<Integer>> sums = new HashMap<>();
ArrayList<Integer> indices = new ArrayList<>();
indices.add(-1);
sums.put(0, indices);
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
indices = sums.get(sum - givenSum);
if(indices != null) {
for(int index : indices) {
System.out.println("From #" + (index + 1) + " to #" + i);
}
if(i - indices.get(indices.size() - 1) < (sEnd - sStart + 1)) {
sStart = indices.get(indices.size() - 1) + 1;
sEnd = i;
}
if(i - indices.get(0) > (lEnd - lStart + 1)) {
lStart = indices.get(0) + 1;
lEnd = i;
}
}
indices = sums.get(sum);
if(indices == null) {
indices = new ArrayList<>();
}
indices.add(i);
sums.put(sum, indices);
}
System.out.println("Shortest sub-arry: Length = " + (sEnd - sStart + 1) + ", [" + sStart + " - " + sEnd + "]");
System.out.println("Longest sub-arry: Length = " + (lEnd - lStart + 1) + ", [" + lStart + " - " + lEnd + "]");
}
Hope this help you.
private static void subArrayZeroSum(int array[] , int findSum){
Map<Integer,HashSet<Integer>> map = new HashMap<Integer,HashSet<Integer>>();
int sum = 0;
for(int index = 0 ; index < array.length ; index ++){
sum +=array[index];
if(array[index] == findSum){
System.out.println(" ["+index+"]");
}
if(sum == findSum && index > 0){
System.out.println(" [ 0 , "+index+" ]");
}
if(map.containsKey(sum)){
HashSet<Integer> set = map.get(sum);
if(set == null)
set = new HashSet<Integer>();
set.add(index);
map.put(sum, set);
for(int val : set){
if(val + 1 != index && (val + 1) < index){
System.out.println("["+(val + 1) +","+index+" ]");
}
}
}else{
HashSet<Integer> set = map.get(sum);
if(set == null)
set = new HashSet<Integer>();
set.add(index);
map.put(sum, set);
}
}
}
One of the solution:
Let's say we have an array of integer,
int[] arr = {2,1,-1,-2};
We will traverse using the for loop until we find the number < 0 OR <= 0
i = 2;
With the inner loop, we will traverse assign the value to j = i-1
So, We can able to find the positive value.
for(int i = 0; i<arr.length; i++){
int j = 0;
int sum = arr[i];
if(arr[i] < 0){
j = i - 1;
}
We will have one sum variable, which maintaining the sum of arr[i] and arr[j] and updating the result.
If the sum is < 0 then, we have to move left side of the array and so, we will decrement the j by one, j--
for(j = i-1; j>=0; j--) {
sum = sum + arr[j];
if(sum == 0){
System.out.println("Index from j=" + j+ " to i=" + i);
return true;
}
}
If the sum is > 0 then, we have to move right side of the array and so, we will increment the i
When we find the sum == 0 then we can print the j and i index and return or break the loop.
And so, It's complete in a linear time. As well we don't need to use any other data structure as well.
Another solution to this problem could be:
1. Calculate sum for entire array
2. Now follow following formula to get the largest subarray with sum zero:
Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
where l=left index, r= right index, initially their value=0 and a.length-1
Idea is simple, max size we can get with sum=0, is the size of array then we start skipping elements from left and right recursively, the moment we get sum=0 we stop. Below is the code for same:
static int find(int a[]) {
int sum =0;
for (int i = 0; i < a.length; i++) {
sum = sum+a[i];
}
return find(a, 0, a.length-1, sum);
}
static int find(int a[], int l, int r, int sum) {
if(l==r && sum>0) {
return 0;
}
if(sum==0) {
return r-l+1;
}
return Math.max(find(a,l+1,r,sum-a[l]), find(a,l,r-1,sum-a[r]));
}
Hope this will help.
int v[DIM] = {2, -3, 1, 2, 3, 1, 4, -6, 7, -5, -1};
int i,j,sum=0,counter=0;
for (i=0; i<DIM; i++) {
sum = v[i];
counter=0;
for (j=i+1; j<DIM;j++) {
sum += v[j];
counter++;
if (sum == 0) {
printf("Sub-array starting from index %d, length %d.\n",(j-counter),counter +1);
}
}
}
Given an array of numbers, find out if 3 of them add up to 0.
Do it in N^2, how would one do this?
O(n^2) solution without hash tables (because using hash tables is cheating :P). Here's the pseudocode:
Sort the array // O(nlogn)
for each i from 1 to len(array) - 1
iter = i + 1
rev_iter = len(array) - 1
while iter < rev_iter
tmp = array[iter] + array[rev_iter] + array[i]
if tmp > 0
rev_iter--
else if tmp < 0
iter++
else
return true
return false
Basically using a sorted array, for each number (target) in an array, you use two pointers, one starting from the front and one starting from the back of the array, check if the sum of the elements pointed to by the pointers is >, < or == to the target, and advance the pointers accordingly or return true if the target is found.
Not for credit or anything, but here is my python version of Charles Ma's solution. Very cool.
def find_sum_to_zero(arr):
arr = sorted(arr)
for i, target in enumerate(arr):
lower, upper = 0, len(arr)-1
while lower < i < upper:
tmp = target + arr[lower] + arr[upper]
if tmp > 0:
upper -= 1
elif tmp < 0:
lower += 1
else:
yield arr[lower], target, arr[upper]
lower += 1
upper -= 1
if __name__ == '__main__':
# Get a list of random integers with no duplicates
from random import randint
arr = list(set(randint(-200, 200) for _ in range(50)))
for s in find_sum_to_zero(arr):
print s
Much later:
def find_sum_to_zero(arr):
limits = 0, len(arr) - 1
arr = sorted(arr)
for i, target in enumerate(arr):
lower, upper = limits
while lower < i < upper:
values = (arr[lower], target, arr[upper])
tmp = sum(values)
if not tmp:
yield values
lower += tmp <= 0
upper -= tmp >= 0
put the negative of each number into a hash table or some other constant time lookup data structure. (n)
loop through the array getting each set of two numbers (n^2), and see if their sum is in the hash table.
First sort the array, then for each negative number (A) in the array, find two elements in the array adding up to -A. Finding 2 elements in a sorted array that add up to the given number takes O(n) time, so the entire time complexity is O(n^2).
C++ implementation based on the pseudocode provided by Charles Ma, for anyone interested.
#include <iostream>
using namespace std;
void merge(int originalArray[], int low, int high, int sizeOfOriginalArray){
// Step 4: Merge sorted halves into an auxiliary array
int aux[sizeOfOriginalArray];
int auxArrayIndex, left, right, mid;
auxArrayIndex = low;
mid = (low + high)/2;
right = mid + 1;
left = low;
// choose the smaller of the two values "pointed to" by left, right
// copy that value into auxArray[auxArrayIndex]
// increment either left or right as appropriate
// increment auxArrayIndex
while ((left <= mid) && (right <= high)) {
if (originalArray[left] <= originalArray[right]) {
aux[auxArrayIndex] = originalArray[left];
left++;
auxArrayIndex++;
}else{
aux[auxArrayIndex] = originalArray[right];
right++;
auxArrayIndex++;
}
}
// here when one of the two sorted halves has "run out" of values, but
// there are still some in the other half; copy all the remaining values
// to auxArray
// Note: only 1 of the next 2 loops will actually execute
while (left <= mid) {
aux[auxArrayIndex] = originalArray[left];
left++;
auxArrayIndex++;
}
while (right <= high) {
aux[auxArrayIndex] = originalArray[right];
right++;
auxArrayIndex++;
}
// all values are in auxArray; copy them back into originalArray
int index = low;
while (index <= high) {
originalArray[index] = aux[index];
index++;
}
}
void mergeSortArray(int originalArray[], int low, int high){
int sizeOfOriginalArray = high + 1;
// base case
if (low >= high) {
return;
}
// Step 1: Find the middle of the array (conceptually, divide it in half)
int mid = (low + high)/2;
// Steps 2 and 3: Recursively sort the 2 halves of origianlArray and then merge those
mergeSortArray(originalArray, low, mid);
mergeSortArray(originalArray, mid + 1, high);
merge(originalArray, low, high, sizeOfOriginalArray);
}
//O(n^2) solution without hash tables
//Basically using a sorted array, for each number in an array, you use two pointers, one starting from the number and one starting from the end of the array, check if the sum of the three elements pointed to by the pointers (and the current number) is >, < or == to the targetSum, and advance the pointers accordingly or return true if the targetSum is found.
bool is3SumPossible(int originalArray[], int targetSum, int sizeOfOriginalArray){
int high = sizeOfOriginalArray - 1;
mergeSortArray(originalArray, 0, high);
int temp;
for (int k = 0; k < sizeOfOriginalArray; k++) {
for (int i = k, j = sizeOfOriginalArray-1; i <= j; ) {
temp = originalArray[k] + originalArray[i] + originalArray[j];
if (temp == targetSum) {
return true;
}else if (temp < targetSum){
i++;
}else if (temp > targetSum){
j--;
}
}
}
return false;
}
int main()
{
int arr[] = {2, -5, 10, 9, 8, 7, 3};
int size = sizeof(arr)/sizeof(int);
int targetSum = 5;
//3Sum possible?
bool ans = is3SumPossible(arr, targetSum, size); //size of the array passed as a function parameter because the array itself is passed as a pointer. Hence, it is cummbersome to calculate the size of the array inside is3SumPossible()
if (ans) {
cout<<"Possible";
}else{
cout<<"Not possible";
}
return 0;
}
This is my approach using Swift 3 in N^2 log N...
let integers = [-50,-40, 10, 30, 40, 50, -20, -10, 0, 5]
First step, sort array
let sortedArray = integers.sorted()
second, implement a binary search method that returns an index like so...
func find(value: Int, in array: [Int]) -> Int {
var leftIndex = 0
var rightIndex = array.count - 1
while leftIndex <= rightIndex {
let middleIndex = (leftIndex + rightIndex) / 2
let middleValue = array[middleIndex]
if middleValue == value {
return middleIndex
}
if value < middleValue {
rightIndex = middleIndex - 1
}
if value > middleValue {
leftIndex = middleIndex + 1
}
}
return 0
}
Finally, implement a method that keeps track of each time a set of "triplets" sum 0...
func getTimesTripleSumEqualZero(in integers: [Int]) -> Int {
let n = integers.count
var count = 0
//loop the array twice N^2
for i in 0..<n {
for j in (i + 1)..<n {
//Sum the first pair and assign it as a negative value
let twoSum = -(integers[i] + integers[j])
// perform a binary search log N
// it will return the index of the give number
let index = find(value: twoSum, in: integers)
//to avoid duplications we need to do this check by checking the items at correspondingly indexes
if (integers[i] < integers[j] && integers[j] < integers[index]) {
print("\([integers[i], integers[j], integers[index]])")
count += 1
}
}
}
return count
}
print("count:", findTripleSumEqualZeroBinary(in: sortedArray))
prints--- count: 7
void findTriplets(int arr[], int n)
{
bool found = false;
for (int i=0; i<n-1; i++)
{
unordered_set<int> s;
for (int j=i+1; j<n; j++)
{
int x = -(arr[i] + arr[j]);
if (s.find(x) != s.end())
{
printf("%d %d %d\n", x, arr[i], arr[j]);
found = true;
}
else
s.insert(arr[j]);
}
}
if (found == false)
cout << " No Triplet Found" << endl;
}