public class MaxSubarray {

   
class Stats {
       
int max;
       
int sum;
       
int count;

       
Stats(int max, int sum, int count) {
           
this.max = max;
           
this.sum = sum;
           
this.count = count;
        }

       
@Override
        public
String toString() {
           
return String.format("Max: %d, Sum: %d, Count: %d, Avg: %.2f",
                   
max, sum, count, (double)sum/count);
        }
    }

   
public void combineUsingStats() {
       
int[][] arrays = {
                {
1, 2, 3},
                {
4, 5, 6},
                {
7, 8, 9}
        };

       
Stats stats = Arrays.stream(arrays)
                .
collect(
                       
// Supplier: Create initial Stats object
                       
() -> new Stats(Integer.MIN_VALUE, 0, 0),

                       
// Accumulator: Process each array
                       
(state, array) -> {
                           
for (int num : array) {
                               
state.max = Math.max(state.max, num);
                               
state.sum += num;
                               
state.count++;
                            }
                        },

                       
// Combiner: Merge two Stats objects
                       
(state1, state2) -> {
                           
state1.max = Math.max(state1.max, state2.max);
                           
state1.sum += state2.sum;
                           
state1.count += state2.count;
                        }
                );

       
System.out.println(stats); // Max: 9, Sum: 45, Count: 9, Avg: 5.00
   
}   

   
public static void combineArraysIntoMap() {

       
String[] arr1 = {"apple", "banana", "orange"};
       
String[] arr2 = {"grape", "kiwi", "mango"};
       
String[] arr3 = {"peach", "plum", "pear"};

       
// Combine arrays with their original array index
       
Map<Integer, List<String>> result = Stream.of(arr1, arr2, arr3)
                .
collect(
                       
// Supplier: Create HashMap
                       
HashMap::new,

                       
// Accumulator: Add array elements to map
                       
(map, array) -> {
                           
int index = map.size(); // Current array index
                           
map.put(index, Arrays.asList(array));
                        },

                       
// Combiner: Merge two maps
                       
(map1, map2) -> map1.putAll(map2)
                );

       
result.forEach((index, list) ->
               
System.out.println("Array " + index + ": " + list));
    }

   
public static void combine3Arrays2() {

       
int[] arr1 = {1, 2, 3};
       
int[] arr2 = {4, 5, 6};
       
int[] arr3 = {7, 8, 9};

       
// Combine three arrays using collect()
       
int[] result = Stream.of(arr1, arr2, arr3)
                .
collect(
                       
// Supplier: Create initial ArrayList
                       
ArrayList<Integer>::new,

                       
// Accumulator: Add each array's elements to the list
                       
(list, array) -> {
                           
for (int num : array) {
                               
list.add(num);
                            }
                        },

                       
// Combiner: Merge two lists (for parallel streams)
                       
(list1, list2) -> list1.addAll(list2)
                )
                .
stream()
                .
mapToInt(Integer::intValue)
                .
toArray();

       
System.out.println(Arrays.toString(result)); // [1, 2, 3, 4, 5, 6, 7, 8, 9]
   
}

   
public static void combine3Arrays() {

       
int[][] arrays = {
                {
1, 2, 3},
                {
4, 5, 6},
                {
7, 8, 9}
        };

       
// Combine and find max from all arrays
       
int[] result = Arrays.stream(arrays)
                .
collect(
                       
// Supplier: Create array [max, sum, count]
                       
() -> new int[]{Integer.MIN_VALUE, 0, 0},

                       
// Accumulator: Process each array
                       
(state, array) -> {
                           
for (int num : array) {
                               
state[0] = Math.max(state[0], num);  // max
                               
state[1] += num;                      // sum
                               
state[2]++;                           // count
                           
}
                        },

                       
// Combiner: Merge two states
                       
(state1, state2) -> {
                           
state1[0] = Math.max(state1[0], state2[0]);  // max of maxes
                           
state1[1] += state2[1];                       // sum of sums
                           
state1[2] += state2[2];                       // count of counts
                       
}
                );

       
System.out.println("Max: " + result[0]);      // 9
       
System.out.println("Sum: " + result[1]);      // 45
       
System.out.println("Count: " + result[2]);    // 9
   
}


   
public static int maxSubarray(int[] arr) {
       
System.out.println(" Question " + Arrays.toString(arr));

       
// Create an array to hold [max, sum] as mutable state
       
int[] result = Arrays.stream(arr).collect(
                ()
-> new int[]{arr[0], 0},  // [max, sum]
               
(state, num) -> {
                   
state[1] += num;
                   
state[0] = Math.max(state[0], state[1]);
                   
if (state[1] < 0) state[1] = 0;
                },
                (
state1, state2) -> {
                   
// Not needed for sequential streams
               
}
        );

       
return result[0];
    }

   
public static int maxSubarray2(int[] arr) {
       
System.out.println(" Question " + Arrays.toString(arr));

       
// Using AtomicInteger to maintain state
       
AtomicInteger sum = new AtomicInteger(0);
       
AtomicInteger max = new AtomicInteger(arr[0]);

       
Arrays.stream(arr).forEach(num -> {
           
sum.addAndGet(num);
           
max.set(Math.max(max.get(), sum.get()));
           
if (sum.get() < 0) sum.set(0);
        });

       
return max.get();
    }

   
public static int maxSubarray1(int[] arr) {

       
System.out.println(" Question " + Arrays.toString(arr));
       
int max = arr[0], sum = 0;
       
for (int i = 0; i < arr.length; i++) {
           
sum += arr[i];
           
max = Math.max(max, sum);

           
System.out.println(
                           
"  c   : " + arr[i] +
                           
", sum : " + sum +
                           
", max : " + max
                   
);


           
if(sum < 0) sum = 0;
        }
       
return max;
    }

   
public static void main (String[] args) {
       
System.out.println("1)" + maxSubarray(new int[]{-2, 5, -1, 7, -3}) + " = 11");
       
System.out.println("2)" + maxSubarray(new int[]{1, -2, 0, 3}) + " = 3");
       
System.out.println("3)" + maxSubarray(new int[]{3, -1, -1, 4, 3, -1}) + " = 8");
       
System.out.println("4)" + maxSubarray(new int[]{1,1,1,1}) + " = 4");
       
System.out.println("5)" + maxSubarray(new int[]{-4, -5, -6}) + " = -4");
       
System.out.println("6)" + maxSubarray(new int[]{10, -2}) + " = 10");
       
System.out.println("7)" + maxSubarray(new int[]{-2, 1, -3, 4, -1, 2, 1, -5, 4}) + " = 6");
       
System.out.println("8)" + maxSubarray(new int[]{-2,1,-3,4,-1,2,1,-5,4}) + " = 6");
       
System.out.println("9)" + maxSubarray(new int[]{-1,1,-1,1,-1}) + " = 1");
       
System.out.println("10)" + maxSubarray(new int[]{-4, 2, 3, -5, 1, 2, -4, 2}) + " = 5");
    }
}