Optimal File Merge Patterns

Last Updated : 23 Sep, 2026

Given an integer array files[], where files[i] represents the size of the i-th sorted file, merge all the files into a single file with the minimum total computation cost.

The cost of merging two files of sizes x and y is x + y. After merging, a new file of size x + y is created, which can be merged further.

Return the minimum total cost required to merge all the files.

Examples: 

Input: files[] = [2, 3, 4]
Output: 14 
Explanation: There are different ways to combine these files. Optimal method is given below:

12

Input: files[] = [2, 3, 4, 5, 6, 7]
Output: 68 
Explanation: Optimal way to combine these files:

13
Try It Yourself
redirect icon

[Naive Approach] Recursion (Try All Possible Merges) - O(n! * n ^ 2) Time and O(n ^ 2) Space

The idea is to try all possible pairs of files for merging and recursively find the minimum cost for the remaining files.

Working of Approach:

  • If only one file remains, return 0 as no more merging is needed.
  • Try every possible pair of files and calculate their merging cost.
  • Create a new array by replacing the selected pair with their combined size.
  • Recursively calculate the minimum cost for the remaining files.
  • Return the minimum total cost among all possible merging choices.
C++
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
using namespace std;

// Recursively find the minimum cost of merging files.
int find(vector<int> &files)
{

    // If only one file remains, no merge is needed.
    if (files.size() <= 1)
        return 0;

    int res = INT_MAX;
    int n = files.size();

    // Try every possible pair of files.
    for (int i = 0; i < n; i++)
    {
        for (int j = i + 1; j < n; j++)
        {

            // Calculate the cost of merging the selected files.
            int cost = files[i] + files[j];

            // Store the remaining files after merging.
            vector<int> nextFiles;

            // Add the merged file to the new array.
            nextFiles.push_back(cost);

            // Add all files except the selected pair.
            for (int k = 0; k < n; k++)
            {
                if (k != i && k != j)
                    nextFiles.push_back(files[k]);
            }

            // Recursively calculate the remaining minimum cost.
            int totalCost = cost + find(nextFiles);

            // Update the minimum total cost.
            res = min(res, totalCost);
        }
    }

    // Return the minimum cost among all merging choices.
    return res;
}

int minComputation(vector<int> &files)
{

    // Start the recursive process.
    return find(files);
}

int main()
{

    vector<int> files = {2, 3, 4};

    cout << minComputation(files) << endl;

    return 0;
}
Java
import java.util.*;

class GFG {

    // Recursively find the minimum cost of merging files.
    public int find(List<Integer> files)
    {

        // If only one file remains, no merge is needed.
        if (files.size() <= 1)
            return 0;

        int res = Integer.MAX_VALUE;
        int n = files.size();

        // Try every possible pair of files.
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {

                // Calculate the cost of merging the
                // selected files.
                int cost = files.get(i) + files.get(j);

                // Store the remaining files after merging.
                List<Integer> nextFiles = new ArrayList<>();

                // Add the merged file to the new array.
                nextFiles.add(cost);

                // Add all files except the selected pair.
                for (int k = 0; k < n; k++) {
                    if (k != i && k != j)
                        nextFiles.add(files.get(k));
                }

                // Recursively calculate the remaining
                // minimum cost.
                int totalCost = cost + find(nextFiles);

                // Update the minimum total cost.
                res = Math.min(res, totalCost);
            }
        }

        // Return the minimum cost among all merging
        // choices.
        return res;
    }

    public int minComputation(int[] files)
    {

        // Convert the array into a list.
        List<Integer> fileList = new ArrayList<>();

        for (int file : files)
            fileList.add(file);

        // Start the recursive process.
        return find(fileList);
    }

    public static void main(String[] args)
    {

        int[] files = { 2, 3, 4 };

        GFG ob = new GFG();

        System.out.println(ob.minComputation(files));
    }
}
Python
def find(files):

    # If only one file remains, no merge is needed.
    if len(files) <= 1:
        return 0

    res = float('inf')
    n = len(files)

    # Try every possible pair of files.
    for i in range(n):
        for j in range(i + 1, n):

            # Calculate the cost of merging the selected files.
            cost = files[i] + files[j]

            # Store the remaining files after merging.
            nextFiles = [cost]

            # Add all files except the selected pair.
            for k in range(n):
                if k!= i and k!= j:
                    nextFiles.append(files[k])

            # Recursively calculate the remaining minimum cost.
            totalCost = cost + find(nextFiles)

            # Update the minimum total cost.
            res = min(res, totalCost)

    # Return the minimum cost among all merging choices.
    return res


def minComputation(files):

    # Start the recursive process.
    return find(files)


if __name__ == '__main__':
    files = [2, 3, 4]
    print(minComputation(files))
C#
using System;
using System.Collections.Generic;

public class GFG {

    // Recursively find the minimum cost of merging files.
    public int Find(List<int> files)
    {

        // If only one file remains, no merge is needed.
        if (files.Count <= 1)
            return 0;

        int res = int.MaxValue;
        int n = files.Count;

        // Try every possible pair of files.
        for (int i = 0; i < n; i++) {
            for (int j = i + 1; j < n; j++) {

                // Calculate the cost of merging the
                // selected files.
                int cost = files[i] + files[j];

                // Store the remaining files after merging.
                List<int> nextFiles = new List<int>();

                // Add the merged file to the new array.
                nextFiles.Add(cost);

                // Add all files except the selected pair.
                for (int k = 0; k < n; k++) {
                    if (k != i && k != j)
                        nextFiles.Add(files[k]);
                }

                // Recursively calculate the remaining
                // minimum cost.
                int totalCost = cost + Find(nextFiles);

                // Update the minimum total cost.
                res = Math.Min(res, totalCost);
            }
        }

        // Return the minimum cost among all merging
        // choices.
        return res;
    }

    public int minComputation(int[] files)
    {

        // Convert the array into a list.
        List<int> fileList = new List<int>(files);

        // Start the recursive process.
        return Find(fileList);
    }

    public static void Main()
    {

        int[] files = { 2, 3, 4 };

        GFG ob = new GFG();

        Console.WriteLine(ob.minComputation(files));
    }
}
JavaScript
function find(files)
{

    // If only one file remains, no merge is needed.
    if (files.length <= 1)
        return 0;

    let res = Number.MAX_SAFE_INTEGER;
    let n = files.length;

    // Try every possible pair of files.
    for (let i = 0; i < n; i++) {
        for (let j = i + 1; j < n; j++) {

            // Calculate the cost of merging the selected
            // files.
            let cost = files[i] + files[j];

            // Store the remaining files after merging.
            let nextFiles = [ cost ];

            // Add all files except the selected pair.
            for (let k = 0; k < n; k++) {
                if (k !== i && k !== j)
                    nextFiles.push(files[k]);
            }

            // Recursively calculate the remaining minimum
            // cost.
            let totalCost = cost + find(nextFiles);

            // Update the minimum total cost.
            res = Math.min(res, totalCost);
        }
    }

    // Return the minimum cost among all merging choices.
    return res;
}

function minComputation(files)
{

    // Start the recursive process.
    return find(files);
}

// Driver Code
let files = [ 2, 3, 4 ];
console.log(minComputation(files));

Output
14

[Expected Approach] Greedy using Min Heap - O(n log n) Time and O(n) Space

The idea is to always merge the two smallest files first using a min heap. This greedy strategy minimizes the total computation cost by choosing the smallest available merging cost at each step.

Why choose the two smallest?

Every merge creates a new file, and that file may be merged again. Therefore, a file's size can contribute to the cost multiple times. The earliest chosen pair, is processed most times, so we choose the smallest.

Working of Approach:

  • Insert all file sizes into a min heap.
  • Extract the two smallest files from the min heap.
  • Merge them and add their sum to the total cost.
  • Insert the newly merged file back into the min heap.
  • Repeat until only one file remains and return the total cost.

Let us understand with an example:
Input: files[] = [2, 3, 4]

  • Insert all files into the min heap: [2, 3, 4], and initialize res = 0.
  • Extract the two smallest files, 2 and 3, merge them with cost 5, update res = 5, and insert 5 back into the heap.
  • Extract the two smallest files, 4 and 5, merge them with cost 9, update res = 14, and insert 9 back into the heap.
  • Only one file remains in the heap, so the loop ends.
  • Return res = 14 as the minimum total computation cost.
12
C++
#include <functional>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

int minComputation(vector<int> &files)
{

    // min heap initialized with all file sizes
    priority_queue<int, vector<int>, greater<int>> pq(files.begin(), files.end());

    int res = 0;
    while (pq.size() > 1)
    {

        // pick two smallest files and merge
        int a = pq.top();
        pq.pop();
        int b = pq.top();
        pq.pop();

        // cost added to res for merging
        res += a + b;
        pq.push(a + b);
    }
    return res;
}

int main()
{

    vector<int> files = {2, 3, 4};

    cout << minComputation(files) << endl;

    return 0;
}
Java
import java.util.PriorityQueue;

public class GFG {

    public static int minComputation(int[] files)
    {

        // Create a min heap.
        PriorityQueue<Integer> pq = new PriorityQueue<>();

        // Add all file sizes to the min heap.
        for (int file : files)
            pq.add(file);

        int res = 0;

        // Continue merging until only one file remains.
        while (pq.size() > 1) {

            // Pick the two smallest files.
            int a = pq.poll();
            int b = pq.poll();

            // Calculate the cost of merging the files.
            int cost = a + b;

            // Add the merging cost to the result.
            res += cost;

            // Add the merged file back to the min heap.
            pq.add(cost);
        }

        // Return the minimum total computation cost.
        return res;
    }

    public static void main(String[] args)
    {

        int[] files = { 2, 3, 4 };

        System.out.println(minComputation(files));
    }
}
Python
import heapq

def minComputation(files):
    # min heap initialized with all file sizes
    pq = files[:]
    heapq.heapify(pq)
    res = 0
    while len(pq) > 1:
        # pick two smallest files and merge
        a = heapq.heappop(pq)
        b = heapq.heappop(pq)
        # cost added to res for merging
        res += a + b
        heapq.heappush(pq, a + b)
    return res

if __name__ == '__main__':
    files = [2, 3, 4]
    print(minComputation(files))
C#
using System;

public class GFG {

    // Min Heap implementation.
    public class MinHeap {

        private int[] heap;
        private int size;

        public MinHeap(int capacity)
        {
            heap = new int[capacity];
            size = 0;
        }

        // Insert an element into the min heap.
        public void Add(int value)
        {

            heap[size] = value;
            int i = size;
            size++;

            // Move the element upwards.
            while (i > 0) {

                int parent = (i - 1) / 2;

                if (heap[parent] <= heap[i])
                    break;

                int temp = heap[parent];
                heap[parent] = heap[i];
                heap[i] = temp;

                i = parent;
            }
        }

        // Remove and return the minimum element.
        public int Poll()
        {

            int res = heap[0];

            size--;
            heap[0] = heap[size];

            int i = 0;

            // Move the root downwards.
            while (true) {

                int left = 2 * i + 1;
                int right = 2 * i + 2;
                int smallest = i;

                if (left < size
                    && heap[left] < heap[smallest])
                    smallest = left;

                if (right < size
                    && heap[right] < heap[smallest])
                    smallest = right;

                if (smallest == i)
                    break;

                int temp = heap[i];
                heap[i] = heap[smallest];
                heap[smallest] = temp;

                i = smallest;
            }

            return res;
        }

        // Return the number of elements.
        public int Count() { return size; }
    }

    public int minComputation(int[] files)
    {

        // Create a min heap.
        MinHeap pq = new MinHeap(files.Length * 2);

        // Add all file sizes to the min heap.
        foreach(int file in files) pq.Add(file);

        int res = 0;

        // Continue merging until only one file remains.
        while (pq.Count() > 1) {

            // Pick the two smallest files.
            int a = pq.Poll();
            int b = pq.Poll();

            // Calculate the cost of merging the files.
            int cost = a + b;

            // Add the merging cost to the result.
            res += cost;

            // Add the merged file back to the min heap.
            pq.Add(cost);
        }

        // Return the minimum total computation cost.
        return res;
    }

    public static void Main()
    {

        int[] files = { 2, 3, 4 };

        GFG ob = new GFG();

        Console.WriteLine(ob.minComputation(files));
    }
}
JavaScript
function minComputation(files)
{
    // min heap initialized with all file sizes
    let pq = files.slice().sort((a, b) => a - b);
    let res = 0;
    while (pq.length > 1) {
        // pick two smallest files and merge
        let a = pq.shift();
        let b = pq.shift();
        // cost added to res for merging
        res += a + b;
        pq.push(a + b);
        pq.sort((a, b) => a - b);
    }
    return res;
}

// Driver Code
let files = [ 2, 3, 4 ];
console.log(minComputation(files));

Output
14
Comment