How to find minimum number of swaps needed to sort an array? [duplicate] - algorithm

I'm working on sorting an integer sequence with no identical numbers (without loss of generality, let's assume the sequence is a permutation of 1,2,...,n) into its natural increasing order (i.e. 1,2,...,n). I was thinking about directly swapping the elements (regardless of the positions of elements; in other words, a swap is valid for any two elements) with minimal number of swaps (the following may be a feasible solution):
Swap two elements with the constraint that either one or both of them should be swapped into the correct position(s). Until every element is put in its correct position.
But I don't know how to mathematically prove if the above solution is optimal. Anyone can help?

I was able to prove this with graph-theory. Might want to add that tag in :)
Create a graph with n vertices. Create an edge from node n_i to n_j if the element in position i should be in position j in the correct ordering. You will now have a graph consisting of several non-intersecting cycles. I argue that the minimum number of swaps needed to order the graph correctly is
M = sum (c in cycles) size(c) - 1
Take a second to convince yourself of that...if two items are in a cycle, one swap can just take care of them. If three items are in a cycle, you can swap a pair to put one in the right spot, and a two-cycle remains, etc. If n items are in a cycle, you need n-1 swaps. (This is always true even if you don't swap with immediate neighbors.)
Given that, you may now be able to see why your algorithm is optimal. If you do a swap and at least one item is in the right position, then it will always reduce the value of M by 1. For any cycle of length n, consider swapping an element into the correct spot, occupied by its neighbor. You now have a correctly ordered element, and a cycle of length n-1.
Since M is the minimum number of swaps, and your algorithm always reduces M by 1 for each swap, it must be optimal.

All the cycle counting is very difficult to keep in your head. There is a way that is much simpler to memorize.
First, let's go through a sample case manually.
Sequence: [7, 1, 3, 2, 4, 5, 6]
Enumerate it: [(0, 7), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (6, 6)]
Sort the enumeration by value: [(1, 1), (3, 2), (2, 3), (4, 4), (5, 5), (6, 6), (0, 7)]
Start from the beginning. While the index is different from the enumerated index keep on swapping the elements defined by index and enumerated index. Remember: swap(0,2);swap(0,3) is the same as swap(2,3);swap(0,2)
swap(0, 1) => [(3, 2), (1, 1), (2, 3), (4, 4), (5, 5), (6, 6), (0, 7)]
swap(0, 3) => [(4, 4), (1, 1), (2, 3), (3, 2), (5, 5), (6, 6), (0, 7)]
swap(0, 4) => [(5, 5), (1, 1), (2, 3), (3, 2), (4, 4), (6, 6), (0, 7)]
swap(0, 5) => [(6, 6), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (0, 7)]
swap(0, 6) => [(0, 7), (1, 1), (2, 3), (3, 2), (4, 4), (5, 5), (6, 6)]
I.e. semantically you sort the elements and then figure out how to put them to the initial state via swapping through the leftmost item that is out of place.
Python algorithm is as simple as this:
def swap(arr, i, j):
arr[i], arr[j] = arr[j], arr[i]
def minimum_swaps(arr):
annotated = [*enumerate(arr)]
annotated.sort(key = lambda it: it[1])
count = 0
i = 0
while i < len(arr):
if annotated[i][0] == i:
i += 1
continue
swap(annotated, i, annotated[i][0])
count += 1
return count
Thus, you don't need to memorize visited nodes or compute some cycle length.

For your reference, here is an algorithm that I wrote, to generate the minimum number of swaps needed to sort the array. It finds the cycles as described by #Andrew Mao.
/**
* Finds the minimum number of swaps to sort given array in increasing order.
* #param ar array of <strong>non-negative distinct</strong> integers.
* input array will be overwritten during the call!
* #return min no of swaps
*/
public int findMinSwapsToSort(int[] ar) {
int n = ar.length;
Map<Integer, Integer> m = new HashMap<>();
for (int i = 0; i < n; i++) {
m.put(ar[i], i);
}
Arrays.sort(ar);
for (int i = 0; i < n; i++) {
ar[i] = m.get(ar[i]);
}
m = null;
int swaps = 0;
for (int i = 0; i < n; i++) {
int val = ar[i];
if (val < 0) continue;
while (val != i) {
int new_val = ar[val];
ar[val] = -1;
val = new_val;
swaps++;
}
ar[i] = -1;
}
return swaps;
}

We do not need to swap the actual elements, just find how many elements are not in the right index (Cycle).
The min swaps will be Cycle - 1;
Here is the code...
static int minimumSwaps(int[] arr) {
int swap=0;
boolean visited[]=new boolean[arr.length];
for(int i=0;i<arr.length;i++){
int j=i,cycle=0;
while(!visited[j]){
visited[j]=true;
j=arr[j]-1;
cycle++;
}
if(cycle!=0)
swap+=cycle-1;
}
return swap;
}

#Archibald, I like your solution, and such was my initial assumptions that sorting the array would be the simplest solution, but I don't see the need to go through the effort of the reverse-traverse as I've dubbed it, ie enumerating then sorting the array and then computing the swaps for the enums.
I find it simpler to subtract 1 from each element in the array and then to compute the swaps required to sort that list
here is my tweak/solution:
def swap(arr, i, j):
tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
def minimum_swaps(arr):
a = [x - 1 for x in arr]
swaps = 0
i = 0
while i < len(a):
if a[i] == i:
i += 1
continue
swap(a, i, a[i])
swaps += 1
return swaps
As for proving optimality, I think #arax has a good point.

// Assuming that we are dealing with only sequence started with zero
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start) {
j = arr[j]
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}

I really liked the solution of #Ieuan Uys in Python.
What I improved on his solution;
While loop is iterated one less to increase speed; while i < len(a) - 1
Swap function is de-capsulated to make one, single function.
Extensive code comments are added to increase readability.
My code in python.
def minimumSwaps(arr):
#make array values starting from zero to match index values.
a = [x - 1 for x in arr]
#initialize number of swaps and iterator.
swaps = 0
i = 0
while i < len(a)-1:
if a[i] == i:
i += 1
continue
#swap.
tmp = a[i] #create temp variable assign it to a[i]
a[i] = a[tmp] #assign value of a[i] with a[tmp]
a[tmp] = tmp #assign value of a[tmp] with tmp (or initial a[i])
#calculate number of swaps.
swaps += 1
return swaps
Detailed explanation on what code does on an array with size n;
We check every value except last one (n-1 iterations) in the array one by one. If the value does not match with array index, then we send this value to its place where index value is equal to its value. For instance, if at a[0] = 3. Then this value should swap with a[3]. a[0] and a[3] is swapped. Value 3 will be at a[3] where it is supposed to be. One value is sent to its place. We have n-2 iteration left. I am not interested what is now a[0]. If it is not 0 at that location, it will be swapped by another value latter. Because that another value also exists in a wrong place, this will be recognized by while loop latter.
Real Example
a[4, 2, 1, 0, 3]
#iteration 0, check a[0]. 4 should be located at a[4] where the value is 3. Swap them.
a[3, 2, 1, 0, 4] #we sent 4 to the right location now.
#iteration 1, check a[1]. 2 should be located at a[2] where the value is 1. Swap them.
a[3, 1, 2, 0, 4] #we sent 2 to the right location now.
#iteration 2, check a[2]. 2 is already located at a[2]. Don't do anything, continue.
a[3, 1, 2, 0, 4]
#iteration 3, check a[3]. 0 should be located at a[0] where the value is 3. Swap them.
a[0, 1, 2, 3, 4] #we sent 0 to the right location now.
# There is no need to check final value of array. Since all swaps are done.

Nicely done solution by #bekce. If using C#, the initial code of setting up the modified array ar can be succinctly expressed as:
var origIndexes = Enumerable.Range(0, n).ToArray();
Array.Sort(ar, origIndexes);
then use origIndexes instead of ar in the rest of the code.

Swift 4 version:
func minimumSwaps(arr: [Int]) -> Int {
struct Pair {
let index: Int
let value: Int
}
var positions = arr.enumerated().map { Pair(index: $0, value: $1) }
positions.sort { $0.value < $1.value }
var indexes = positions.map { $0.index }
var swaps = 0
for i in 0 ..< indexes.count {
var val = indexes[i]
if val < 0 {
continue // Already visited.
}
while val != i {
let new_val = indexes[val]
indexes[val] = -1
val = new_val
swaps += 1
}
indexes[i] = -1
}
return swaps
}

This is the sample code in C++ that finds the minimum number of swaps to sort a permutation of the sequence of (1,2,3,4,5,.......n-2,n-1,n)
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n,i,j,k,num = 0;
cin >> n;
int arr[n+1];
for(i = 1;i <= n;++i)cin >> arr[i];
for(i = 1;i <= n;++i)
{
if(i != arr[i])// condition to check if an element is in a cycle r nt
{
j = arr[i];
arr[i] = 0;
while(j != 0)// Here i am traversing a cycle as mentioned in
{ // first answer
k = arr[j];
arr[j] = j;
j = k;
num++;// reducing cycle by one node each time
}
num--;
}
}
for(i = 1;i <= n;++i)cout << arr[i] << " ";cout << endl;
cout << num << endl;
return 0;
}

Solution using Javascript.
First I set all the elements with their current index that need to be ordered, and then I iterate over the map to order only the elements that need to be swapped.
function minimumSwaps(arr) {
const mapUnorderedPositions = new Map()
for (let i = 0; i < arr.length; i++) {
if (arr[i] !== i+1) {
mapUnorderedPositions.set(arr[i], i)
}
}
let minSwaps = 0
while (mapUnorderedPositions.size > 1) {
const currentElement = mapUnorderedPositions.entries().next().value
const x = currentElement[0]
const y = currentElement[1]
// Skip element in map if its already ordered
if (x-1 !== y) {
// Update unordered position index of swapped element
mapUnorderedPositions.set(arr[x-1], y)
// swap in array
arr[y] = arr[x-1]
arr[x-1] = x
// Increment swaps
minSwaps++
}
mapUnorderedPositions.delete(x)
}
return minSwaps
}
If you have an input like 7 2 4 3 5 6 1, this is how the debugging will go:
Map { 7 => 0, 4 => 2, 3 => 3, 1 => 6 }
currentElement [ 7, 0 ]
swapping 1 with 7
[ 1, 2, 4, 3, 5, 6, 7 ]
currentElement [ 4, 2 ]
swapping 3 with 4
[ 1, 2, 3, 4, 5, 6, 7 ]
currentElement [ 3, 2 ]
skipped
minSwaps = 2

Finding the minimum number of swaps required to put a permutation of 1..N in order.
We can use that the we know what the sort result would be: 1..N, which means we don't actually have to do swaps just count them.
The shuffling of 1..N is called a permutation, and is composed of disjoint cyclic permutations, for example, this permutation of 1..6:
1 2 3 4 5 6
6 4 2 3 5 1
Is composed of the cyclic permutations (1,6)(2,4,3)(5)
1->6(->1) cycle: 1 swap
2->4->3(->2) cycle: 2 swaps
5(->5) cycle: 0 swaps
So a cycle of k elements requires k-1 swaps to put in order.
Since we know where each element "belongs" (i.e. value k belongs at position k-1) we can easily traverse the cycle. Start at 0, we get 6, which belongs at 5,
and there we find 1, which belongs at 0 and we're back where we started.
To avoid re-counting a cycle later, we track which elements were visited - alternatively you could perform the swaps so that the elements are in the right place when you visit them later.
The resulting code:
def minimumSwaps(arr):
visited = [False] * len(arr)
numswaps = 0
for i in range(len(arr)):
if not visited[i]:
visited[i] = True
j = arr[i]-1
while not visited[j]:
numswaps += 1
visited[j] = True
j = arr[j]-1
return numswaps

An implementation on integers with primitive types in Java (and tests).
import java.util.Arrays;
public class MinSwaps {
public static int computate(int[] unordered) {
int size = unordered.length;
int[] ordered = order(unordered);
int[] realPositions = realPositions(ordered, unordered);
boolean[] touchs = new boolean[size];
Arrays.fill(touchs, false);
int i;
int landing;
int swaps = 0;
for(i = 0; i < size; i++) {
if(!touchs[i]) {
landing = realPositions[i];
while(!touchs[landing]) {
touchs[landing] = true;
landing = realPositions[landing];
if(!touchs[landing]) { swaps++; }
}
}
}
return swaps;
}
private static int[] realPositions(int[] ordered, int[] unordered) {
int i;
int[] positions = new int[unordered.length];
for(i = 0; i < unordered.length; i++) {
positions[i] = position(ordered, unordered[i]);
}
return positions;
}
private static int position(int[] ordered, int value) {
int i;
for(i = 0; i < ordered.length; i++) {
if(ordered[i] == value) {
return i;
}
}
return -1;
}
private static int[] order(int[] unordered) {
int[] ordered = unordered.clone();
Arrays.sort(ordered);
return ordered;
}
}
Tests
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class MinimumSwapsSpec {
#Test
public void example() {
// setup
int[] unordered = new int[] { 40, 23, 1, 7, 52, 31 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(5, minSwaps);
}
#Test
public void example2() {
// setup
int[] unordered = new int[] { 4, 3, 2, 1 };
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
#Test
public void example3() {
// setup
int[] unordered = new int[] {1, 5, 4, 3, 2};
// run
int minSwaps = MinSwaps.computate(unordered);
// verify
assertEquals(2, minSwaps);
}
}

Swift 4.2:
func minimumSwaps(arr: [Int]) -> Int {
let sortedValueIdx = arr.sorted().enumerated()
.reduce(into: [Int: Int](), { $0[$1.element] = $1.offset })
var checked = Array(repeating: false, count: arr.count)
var swaps = 0
for idx in 0 ..< arr.count {
if checked[idx] { continue }
var edges = 1
var cursorIdx = idx
while true {
let cursorEl = arr[cursorIdx]
let targetIdx = sortedValueIdx[cursorEl]!
if targetIdx == idx {
break
} else {
cursorIdx = targetIdx
edges += 1
}
checked[targetIdx] = true
}
swaps += edges - 1
}
return swaps
}

Python code
A = [4,3,2,1]
count = 0
for i in range (len(A)):
min_idx = i
for j in range (i+1,len(A)):
if A[min_idx] > A[j]:
min_idx = j
if min_idx > i:
A[i],A[min_idx] = A[min_idx],A[i]
count = count + 1
print "Swap required : %d" %count

In Javascript
If the count of the array starts with 1
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start + 1) {
j = arr[j] - 1
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
else for input starting with 0
function minimumSwaps(arr) {
var len = arr.length
var visitedarr = []
var i, start, j, swap = 0
for (i = 0; i < len; i++) {
if (!visitedarr[i]) {
start = j = i
var cycleNode = 1
while (arr[j] != start) {
j = arr[j]
visitedarr[j] = true
cycleNode++
}
swap += cycleNode - 1
}
}
return swap
}
Just extending Darshan Puttaswamy code for current HackerEarth inputs

Here's a solution in Java for what #Archibald has already explained.
static int minimumSwaps(int[] arr){
int swaps = 0;
int[] arrCopy = arr.clone();
HashMap<Integer, Integer> originalPositionMap
= new HashMap<>();
for(int i = 0 ; i < arr.length ; i++){
originalPositionMap.put(arr[i], i);
}
Arrays.sort(arr);
for(int i = 0 ; i < arr.length ; i++){
while(arr[i] != arrCopy[i]){
//swap
int temp = arr[i];
arr[i] = arr[originalPositionMap.get(temp)];
arr[originalPositionMap.get(temp)] = temp;
swaps += 1;
}
}
return swaps;
}

def swap_sort(arr)
changes = 0
loop do
# Find a number that is out-of-place
_, i = arr.each_with_index.find { |val, index| val != (index + 1) }
if i != nil
# If such a number is found, then `j` is the position that the out-of-place number points to.
j = arr[i] - 1
# Swap the out-of-place number with number from position `j`.
arr[i], arr[j] = arr[j], arr[i]
# Increase swap counter.
changes += 1
else
# If there are no out-of-place number, it means the array is sorted, and we're done.
return changes
end
end
end

Apple Swift version 5.2.4
func minimumSwaps(arr: [Int]) -> Int {
var swapCount = 0
var arrayPositionValue = [(Int, Int)]()
var visitedDictionary = [Int: Bool]()
for (index, number) in arr.enumerated() {
arrayPositionValue.append((index, number))
visitedDictionary[index] = false
}
arrayPositionValue = arrayPositionValue.sorted{ $0.1 < $1.1 }
for i in 0..<arr.count {
var cycleSize = 0
var visitedIndex = i
while !visitedDictionary[visitedIndex]! {
visitedDictionary[visitedIndex] = true
visitedIndex = arrayPositionValue[visitedIndex].0
cycleSize += 1
}
if cycleSize > 0 {
swapCount += cycleSize - 1
}
}
return swapCount
}

Go version 1.17:
func minimumSwaps(arr []int32) int32 {
var swap int32
for i := 0; i < len(arr) - 1; i++{
for j := 0; j < len(arr); j++ {
if arr[j] > arr[i] {
arr[i], arr[j] = arr[j], arr[i]
swap++
}else {
continue
}
}
}
return swap
}

Related

How to get the number of the Subarray with at least K different numbers?

The question is:
"Given an array A only contains integers Return the number of subarrays that contain at least k different numbers. Subarrays cannot be duplicated."
Example:
input array = {1, 2, 3, 4, 2} k = 3
output: 4
Explanation:
the number of the Subarray with at least K different numbers should be 4,
which are [1, 2, 3] [2, 3, 4] [3, 4, 2] [1, 2, 3, 4]
Right now what I can do is just find about the number of the subarray with exactly K different numbers:
class Solution {
public int subarraysWithKDistinct(int[] A, int K) {
return atMostK(A, K) - atMostK(A, K - 1);
}
private int atMostK(int[] A, int K) {
int i = 0, res = 0;
Map<Integer, Integer> count = new HashMap<>();
for (int j = 0; j < A.length; ++j) {
if (count.getOrDefault(A[j], 0) == 0) K--;
count.put(A[j], count.getOrDefault(A[j], 0) + 1);
while (K < 0) {
count.put(A[i], count.get(A[i]) - 1);
if (count.get(A[i]) == 0) K++;
i++;
}
res += j - i + 1;
}
return res;
}
}
But when the input be:
array = {1, 2, 3, 4, 2} k = 2
my code will not work correctly, but I don't know where to change. Any thoughts? Thanks!
Update: thanks to #MBo and others' answers, I used 2 pointers to fix this problem, but still cannot get the right answer with:
array = {1, 2, 3, 4, 2} k = 3 -> output: 6 (should be 4)
It looks like there are some duplicated substrings be counted, but I don't know how to fix it.
class Solution {
public static void main(String[] args) {
int[] A = {1, 2, 3, 4, 2};
int k = 3;
int res = helper(A, k);
System.out.println(res);
// output is 6, but should be 4
}
private static int helper(int[] A, int k) {
if (A == null || A.length == 0) return 0;
int n = A.length;
int res = 0;
int differentNumbers = 0;
Map<Integer, Integer> counter = new HashMap<>();
int j = 0; // j - 1 is the right point
for (int i = 0; i < n; i ++) {
while (j < n && differentNumbers < k) {
int numOfThisNumber = counter.getOrDefault(A[j], 0);
counter.put(A[j], numOfThisNumber + 1);
if (counter.get(A[j]) == 1) {
differentNumbers ++;
}
j ++;
}
if (differentNumbers == k) {
res += n - j + 1;
}
counter.put(A[i], counter.get(A[i]) - 1);
if (counter.get(A[i]) == 0) {
differentNumbers --;
}
}
return res;
}
}
You can combine your hashmap approach with method of two pointers (indices).
Set both indices into 0 and move right one, updating hashmap counts for values at the right end of interval until hashmap size reaches K. Fix right index.
Now move left index, decreasing counts corresponding to the values at left end. Before every step (including left=0) add size-right to result, because all subarrays starting from left and ending after right, do contain needed number of elements.
When some count becomes 0, remove value from hashmap, and fix left index.
Repeat with right index and so on.

sum of array elements(any order) equal to k not continuous elements [duplicate]

This question already has an answer here:
subset sum find all subsets that add up to a number
(1 answer)
Closed 2 years ago.
I have 2 input
array: {3,6,9,0,2,1,3} // positive number and can repeat also
Sum = 9
Need to find a combination(order not mandatory) of array element which has total to Sum(here for example it's 9).
Output expected :
{3,6}
{9}
{6,3}
{3,2,1,3}
I am not able to solve it. So, please don't ask for my solution. Please help by solving in java.
This problem can be solved by printing all the subsets with given sum.
Have a look at the following implementation:
// A Java program to count all subsets with given sum.
import java.util.ArrayList;
public class SubSet_sum_problem
{
// dp[i][j] is going to store true if sum j is
// possible with array elements from 0 to i.
static boolean[][] dp;
static void display(ArrayList<Integer> v)
{
System.out.println(v);
}
// A recursive function to print all subsets with the
// help of dp[][]. Vector p[] stores current subset.
static void printSubsetsRec(int arr[], int i, int sum,
ArrayList<Integer> p)
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if (i == 0 && sum != 0 && dp[0][sum])
{
p.add(arr[i]);
display(p);
p.clear();
return;
}
// If sum becomes 0
if (i == 0 && sum == 0)
{
display(p);
p.clear();
return;
}
// If given sum can be achieved after ignoring
// current element.
if (dp[i-1][sum])
{
// Create a new vector to store path
ArrayList<Integer> b = new ArrayList<>();
b.addAll(p);
printSubsetsRec(arr, i-1, sum, b);
}
// If given sum can be achieved after considering
// current element.
if (sum >= arr[i] && dp[i-1][sum-arr[i]])
{
p.add(arr[i]);
printSubsetsRec(arr, i-1, sum-arr[i], p);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
static void printAllSubsets(int arr[], int n, int sum)
{
if (n == 0 || sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
dp = new boolean[n][sum + 1];
for (int i=0; i<n; ++i)
{
dp[i][0] = true;
}
// Sum arr[0] can be achieved with single element
if (arr[0] <= sum)
dp[0][arr[0]] = true;
// Fill rest of the entries in dp[][]
for (int i = 1; i < n; ++i)
for (int j = 0; j < sum + 1; ++j)
dp[i][j] = (arr[i] <= j) ? (dp[i-1][j] ||
dp[i-1][j-arr[i]])
: dp[i - 1][j];
if (dp[n-1][sum] == false)
{
System.out.println("There are no subsets with" +
" sum "+ sum);
return;
}
// Now recursively traverse dp[][] to find all
// paths from dp[n-1][sum]
ArrayList<Integer> p = new ArrayList<>();
printSubsetsRec(arr, n-1, sum, p);
}
//Driver Program to test above functions
public static void main(String args[])
{
int arr[] = {3, 6, 9, 0, 2, 1, 3};
int n = arr.length;
int sum = 9;
printAllSubsets(arr, n, sum);
}
}
Output:
[6, 3]
[9]
[0, 6, 3]
[0, 9]
[1, 2, 6]
[1, 2, 0, 6]
[3, 6]
[3, 0, 6]
[3, 1, 2, 3]
[3, 1, 2, 0, 3]

Competitive programming - Prepare the perfect curry with ingredients P, Q, and R

Recently i got a competetive programming task which i couldn't manage to complete. Just curious to know the best solution for the problem
"A" is a zero-indexed array of N integers.
Elements of A are integers within the range [−99,999,999 to 99,999,999]
The 'curry' is a string consisting of N characters such that each character is either 'P', 'Q' or 'R' and the
corresponding index of the array is the weight of each ingredient.
The curry is perfect if the sum of the total weights of 'P', 'Q' and 'R' is equal.
write a function
makeCurry(Array)
such that, given a zero-indexed array Array consisting of N integers, returns the perfect curry of this array.
The function should return the string "noLuck" if no perfect curry exists for that Array.
For example, given array Array such that
A[0] = 3 A[1] = 7 A[2] = 2 A[3] = 5 A[4] = 4
the function may return "PQRRP", as explained above. Given array A such that
A[0] = 3 A[1] = 6 A[2] = 9
the function should return "noLuck".
The approach i tried was this
import collections
class GetPerfectCurry(object):
def __init__(self):
self.curry = ''
self.curry_stats = collections.Counter({'P': 0, 'Q': 0, 'R': 0})
pass
def get_perfect_curry(self, A):
if len(A) == 0:
return "noLuck"
A.sort(reverse=True)
for i, ele in enumerate(A):
self.check_which_key_to_add_new_element_and_add_element(ele)
if self.curry_stats['P'] == self.curry_stats['Q'] == self.curry_stats['R']:
return self.curry
else:
return "noLuck"
def check_which_key_to_add_new_element_and_add_element(self, val):
# get the maximum current value
# check if addition of new value with any of the other two key equals the max value
# if yes then add that value and append the key in the curry string
current_max_key = max(self.curry_stats, key=self.curry_stats.get)
check_for_equality = False
key_to_append = None
for key, ele in enumerate(self.curry_stats):
if ele != current_max_key:
if self.curry_stats[ele] + val == self.curry_stats[current_max_key]:
check_for_equality = True
key_to_append = ele
if check_for_equality:
self.curry_stats.update(str(key_to_append) * val)
self.curry += str(key_to_append)
pass
else:
# if no value addition equals the current max
# then find the current lowest value and add it to that key
current_lowest_key = min(self.curry_stats, key=self.curry_stats.get)
self.curry_stats.update(str(current_lowest_key)*val)
self.curry += str(current_lowest_key)
if __name__ == '__main__':
perfect_curry = GetPerfectCurry()
A = [3, 7, 2, 5, 4]
# A = [3, 6, 9]
# A = [2, 9, 6, 3, 7]
res = perfect_curry.get_perfect_curry(A)
print(res)
But it was incorrect. Scratching my head for the past four hours for the best solution for this problem
A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
Here's a Java implementation (I'm not a Python guy, sorry):
import java.util.Arrays;
public class Main
{
// Test if selected elements add up to target
static boolean check(int[] a, int selection, int target)
{
int sum = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
static int[] exclude(int[] a, int selection)
{
int[] res = new int[a.length];
int j = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return Arrays.copyOf(res, j);
}
static String getCurry(int[] a)
{
int sum = 0;
for(int x : a)
sum += x;
if(sum%3 > 0)
return "noLuck";
int target = sum/3;
int max1 = 1<<a.length; // 2^length
for(int i=0;i<max1;i++)
{
if(check(a, i, target))
{
int[] b = exclude(a, i);
int max2 = 1<<b.length; // 2^length
for(int j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
static String formatSolution(int p, int q, int len)
{
char[] res = new char[len];
Arrays.fill(res, 'R');
int j = 0;
for(int i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
public static void main(String[] args)
{
// int[] a = new int[]{3, 7, 2, 5, 4};
// int[] a = new int[]{1, 1, 2, -1};
int[] a = new int[]{5, 4, 3, 3, 3, 3, 3, 3};
System.out.println(getCurry(a));
}
}
You can test it here.
Hereafter so many years I'm writing code for js for needed people. (TBH I took the ref of the accepted answer)
As he mentioned, A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
// Test if selected elements add up to target
function check(a, selection, target)
{
let sum = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
function exclude(a, selection)
{
let res = [a.length];
let j = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return res
}
function getCurry(a)
{
let sum = a.reduce((accumulator, currentValue) => accumulator + currentValue);
if(sum%3 > 0)
return "noLuck";
let target = sum/3;
let max1 = 1<<a.length; // 2^length
for(let i=0;i<max1;i++)
{
if(check(a, i, target))
{
let b = exclude(a, i);
let max2 = 1<<b.length; // 2^length
for(let j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
function formatSolution(p, q, len)
{
let res = new Array(len)
res.fill('R')
let j = 0;
for(let i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
// let a = [3, 7, 2, 5, 4]
// let a = [1, 1, 2, -1]
let a = [5, 4, 3, 3, 3, 3, 3, 3]
getCurry(a)

Find the first "missing" number in a sorted list

Let's say I have the continuous range of integers [0, 1, 2, 4, 6], in which the 3 is the first "missing" number. I need an algorithm to find this first "hole". Since the range is very large (containing perhaps 2^32 entries), efficiency is important. The range of numbers is stored on disk; space efficiency is also a main concern.
What's the best time and space efficient algorithm?
Use binary search. If a range of numbers has no hole, then the difference between the end and start of the range will also be the number of entries in the range.
You can therefore begin with the entire list of numbers, and chop off either the first or second half based on whether the first half has a gap. Eventually you will come to a range with two entries with a hole in the middle.
The time complexity of this is O(log N). Contrast to a linear scan, whose worst case is O(N).
Based on the approach suggested by #phs above, here is the C code to do that:
#include <stdio.h>
int find_missing_number(int arr[], int len) {
int first, middle, last;
first = 0;
last = len - 1;
middle = (first + last)/2;
while (first < last) {
if ((arr[middle] - arr[first]) != (middle - first)) {
/* there is a hole in the first half */
if ((middle - first) == 1 && (arr[middle] - arr[first] > 1)) {
return (arr[middle] - 1);
}
last = middle;
} else if ((arr[last] - arr[middle]) != (last - middle)) {
/* there is a hole in the second half */
if ((last - middle) == 1 && (arr[last] - arr[middle] > 1)) {
return (arr[middle] + 1);
}
first = middle;
} else {
/* there is no hole */
return -1;
}
middle = (first + last)/2;
}
/* there is no hole */
return -1;
}
int main() {
int arr[] = {3, 5, 1};
printf("%d", find_missing_number(arr, sizeof arr/(sizeof arr[0]))); /* prints 4 */
return 0;
}
Since numbers from 0 to n - 1 are sorted in an array, the first numbers should be same as their indexes. That's to say, the number 0 is located at the cell with index 0, the number 1 is located at the cell with index 1, and so on. If the missing number is denoted as m. Numbers less then m are located at cells with indexes same as values.
The number m + 1 is located at a cell with index m, The number m + 2 is located at a cell with index m + 1, and so on. We can see that, the missing number m is the first cell whose value is not identical to its value.
Therefore, it is required to search in an array to find the first cell whose value is not identical to its value. Since the array is sorted, we could find it in O(lg n) time based on the binary search algorithm as implemented below:
int getOnceNumber_sorted(int[] numbers)
{
int length = numbers.length
int left = 0;
int right = length - 1;
while(left <= right)
{
int middle = (right + left) >> 1;
if(numbers[middle] != middle)
{
if(middle == 0 || numbers[middle - 1] == middle - 1)
return middle;
right = middle - 1;
}
else
left = middle + 1;
}
return -1;
}
This solution is borrowed from my blog: http://codercareer.blogspot.com/2013/02/no-37-missing-number-in-array.html.
Based on algorithm provided by #phs
int findFirstMissing(int array[], int start , int end){
if(end<=start+1){
return start+1;
}
else{
int mid = start + (end-start)/2;
if((array[mid] - array[start]) != (mid-start))
return findFirstMissing(array, start, mid);
else
return findFirstMissing(array, mid+1, end);
}
}
Below is my solution, which I believe is simple and avoids an excess number of confusing if-statements. It also works when you don't start at 0 or have negative numbers involved! The complexity is O(lg(n)) time with O(1) space, assuming the client owns the array of numbers (otherwise it's O(n)).
The Algorithm in C Code
int missingNumber(int a[], int size) {
int lo = 0;
int hi = size - 1;
// TODO: Use this if we need to ensure we start at 0!
//if(a[0] != 0) { return 0; }
// All elements present? If so, return next largest number.
if((hi-lo) == (a[hi]-a[lo])) { return a[hi]+1; }
// While 2 or more elements to left to consider...
while((hi-lo) >= 2) {
int mid = (lo + hi) / 2;
if((mid-lo) != (a[mid]-a[lo])) { // Explore left-hand side
hi = mid;
} else { // Explore right hand side
lo = mid + 1;
}
}
// Return missing value from the two candidates remaining...
return (lo == (a[lo]-a[0])) ? hi + a[0] : lo + a[0];
}
Test Outputs
int a[] = {0}; // Returns: 1
int a[] = {1}; // Returns: 2
int a[] = {0, 1}; // Returns: 2
int a[] = {1, 2}; // Returns: 3
int a[] = {0, 2}; // Returns: 1
int a[] = {0, 2, 3, 4}; // Returns: 1
int a[] = {0, 1, 2, 4}; // Returns: 3
int a[] = {0, 1, 2, 4, 5, 6, 7, 8, 9}; // Returns: 3
int a[] = {2, 3, 5, 6, 7, 8, 9}; // Returns: 4
int a[] = {2, 3, 4, 5, 6, 8, 9}; // Returns: 7
int a[] = {-3, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Returns: -1
int a[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Returns: 10
The general procedure is:
(Optional) Check if the array starts at 0. If it doesn't, return 0 as missing.
Check if the array of integers is complete with no missing integer. If it is not missing an integer, return the next largest integer.
In a binary search fashion, check for a mismatch between the difference in the indices and array values. A mismatch tells us which half a missing element is in. If there is a mismatch in the first half, move left, otherwise move right. Do this until you have two candidate elements left to consider.
Return the number that is missing based on incorrect candidate.
Note, the algorithm's assumptions are:
First and last elements are considered to never be missing. These elements establish a range.
Only one integer is ever missing in the array. This will not find more than one missing integer!
Integer in the array are expected to increase in steps of 1, not at any other rate.
Have you considered a run-length encoding? That is, you encode the first number as well as the count of numbers that follow it consecutively. Not only can you represent the numbers used very efficiently this way, the first hole will be at the end of the first run-length encoded segment.
To illustrate with your example:
[0, 1, 2, 4, 6]
Would be encoded as:
[0:3, 4:1, 6:1]
Where x:y means there is a set of numbers consecutively starting at x for y numbers in a row. This tells us immediately that the first gap is at location 3. Note, however, that this will be much more efficient when the assigned addresses are clustered together, not randomly dispersed throughout the range.
if the list is sorted, I'd iterate over the list and do something like this Python code:
missing = []
check = 0
for n in numbers:
if n > check:
# all the numbers in [check, n) were not present
missing += range(check, n)
check = n + 1
# now we account for any missing numbers after the last element of numbers
if check < MAX:
missing += range(check, MAX + 1)
if lots of numbers are missing, you might want to use #Nathan's run-length encoding suggestion for the missing list.
Missing
Number=(1/2)(n)(n+1)-(Sum of all elements in the array)
Here n is the size of array+1.
Array: [1,2,3,4,5,6,8,9]
Index: [0,1,2,3,4,5,6,7]
int findMissingEmementIndex(int a[], int start, int end)
{
int mid = (start + end)/2;
if( Math.abs(a[mid] - a[start]) != Math.abs(mid - start) ){
if( Math.abs(mid - start) == 1 && Math.abs(a[mid] - a[start])!=1 ){
return start +1;
}
else{
return findMissingElmementIndex(a,start,mid);
}
}
else if( a[mid] - a[end] != end - start){
if( Math.abs(end - mid) ==1 && Math.abs(a[end] - a[mid])!=1 ){
return mid +1;
}
else{
return findMissingElmementIndex(a,mid,end);
}
}
else{
return No_Problem;
}
}
This is an interview Question. We will have an array of more than one missing numbers and we will put all those missing numbers in an ArrayList.
public class Test4 {
public static void main(String[] args) {
int[] a = { 1, 3, 5, 7, 10 };
List<Integer> list = new ArrayList<>();
int start = 0;
for (int i = 0; i < a.length; i++) {
int ch = a[i];
if (start == ch) {
start++;
} else {
list.add(start);
start++;
i--; // a must do.
} // else
} // for
System.out.println(list);
}
}
Functional Programming solution (Scala)
Nice and elegant
Lazy evaluation
def gapFinder(sortedList: List[Int], start: Int = 0): Int = {
def withGuards: Stream[Int] =
(start - 1) +: sortedList.toStream :+ (sortedList.last + 2)
if (sortedList.isEmpty) start
else withGuards.sliding(2)
.dropWhile { p => p.head + 1 >= p.last }.next()
.headOption.getOrElse(start) + 1
} // 8-line solution
// Tests
assert(gapFinder(List()) == 0)
assert(gapFinder(List[Int](0)) == 1)
assert(gapFinder(List[Int](1)) == 0)
assert(gapFinder(List[Int](2)) == 0)
assert(gapFinder(List[Int](0, 1, 2)) == 3)
assert(gapFinder(List[Int](0, 2, 4)) == 1)
assert(gapFinder(List[Int](0, 1, 2, 4)) == 3)
assert(gapFinder(List[Int](0, 1, 2, 4, 5)) == 3)
import java.util.Scanner;
class MissingNumber {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] arr =new int[n];
for (int i=0;i<n;i++){
arr[i]=scan.nextInt();
}
for (int i=0;i<n;i++){
if(arr[i+1]==arr[i]+1){
}
else{
System.out.println(arr[i]+1);
break;
}
}
}
}
I was looking for a super simple way to find the first missing number in a sorted array with a max potential value in javascript and didn't have to worry about efficiency too much as I didn't plan on using a list longer 10-20 items at the most. This is the recursive function I came up with:
function findFirstMissingNumber(sortedList, index, x, maxAllowedValue){
if(sortedList[index] == x && x < maxAllowedValue){
return findFirstMissingNumber(sortedList, (index+1), (x+1), maxAllowedValue);
}else{ return x; }
}
findFirstMissingNumber([3, 4, 5, 7, 8, 9], 0, 3, 10);
//expected output: 6
Give it your array, the index you wish to start at, the value you expect it to be and the maximum value you'd like to check up to.
i got one algorithm for finding the missing number in the sorted list. its complexity is logN.
public int execute2(int[] array) {
int diff = Math.min(array[1]-array[0], array[2]-array[1]);
int min = 0, max = arr.length-1;
boolean missingNum = true;
while(min<max) {
int mid = (min + max) >>> 1;
int leftDiff = array[mid] - array[min];
if(leftDiff > diff * (mid - min)) {
if(mid-min == 1)
return (array[mid] + array[min])/2;
max = mid;
missingNum = false;
continue;
}
int rightDiff = array[max] - array[mid];
if(rightDiff > diff * (max - mid)) {
if(max-mid == 1)
return (array[max] + array[mid])/2;
min = mid;
missingNum = false;
continue;
}
if(missingNum)
break;
}
return -1;
}
Based on algorithm provided by #phs
public class Solution {
public int missing(int[] array) {
// write your solution here
if(array == null){
return -1;
}
if (array.length == 0) {
return 1;
}
int left = 0;
int right = array.length -1;
while (left < right - 1) {
int mid = left + (right - left) / 2;
if (array[mid] - array[left] != mid - left) { //there is gap in [left, mid]
right = mid;
}else if (array[right] - array[mid] != right - mid) { //there is gap in [mid, right]
left = mid;
}else{ //there is no gapin [left, right], which means the missing num is the at 0 and N
return array[0] == 1 ? array.length + 1 : 1 ;
}
}
if (array[right] - array[left] == 2){ //missing number is between array[left] and array[right]
return left + 2;
}else{
return array[0] == 1 ? -1 : 1; //when ther is only one element in array
}
}
}
public static int findFirst(int[] arr) {
int l = -1;
int r = arr.length;
while (r - l > 1) {
int middle = (r + l) / 2;
if (arr[middle] > middle) {
r = middle;
}
l = middle;
}
return r;
}

maximum subarray whose sum equals 0

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);
}
}
}

Resources