Talentd
FleetCode
Make and follow sheets.Sign in

Total Cost to Hire K Workers solution and explanation

MediumArrayHeap (Priority Queue)SimulationTwo Pointers8 min read43.6% acceptanceUpdated 9 Apr 2026
Total Cost to Hire K Workers | Using 2 Heap | Dry Run | META | Leetcode-2462 | Live CodecodestorywithMIK · 25:47 · 13K viewsWatch on YouTube
9 more videos on this problem
  1. Total Cost to Hire K Workers | Using 2 Heap | Dry Run | META | Leetcode-2462 | Live CodecodestorywithMIK · 25:47 · 13K views
  2. Total Cost to Hire K Workers II Greedy II Min Heap II Priority Queue II 2 Pointers II Leetcode 2462Aryan Mittal · 13:45 · 10K views
  3. Total Cost to Hire K Workers #leetcode #leetcode75 #heapDeepti Talesra · 13:14 · 2K views
  4. Leetcode Weekly Contest 318 | 2462 : Total Cost To Hire K Workers Solution | Newton SchoolCoding Community | Newton School · 16:15 · 2K views
  5. 2462. Total Cost to Hire K Workers | Min-Heap | Two Pointers | LeetCode Daily ChallengeDeep Tech · 22:14 · 1K views
  6. 2462. Total Cost to Hire K Workers (Leetcode Medium)Programming Live with Larry · 13:56 · 1K views
  7. Total Cost to Hire K Workers - LeetCode 2462 - PythonAlpha-Code · 14:16 · 1K views
  8. Why NOT Segment Trees? | Weekly Contest 318 | Total Cost to Hire K WorkerscodingMohan · 17:21 · 794 views
  9. Leetcode Weekly contest 318 - Medium - Total Cost to Hire K WorkersPrakhar Agrawal · 14:48 · 574 views
  10. 2462. Total Cost to Hire K Workers | JavaScript | Min Heap | LeetCode Daily ChallengeLeetCodeWithMonu · 21:41 · 328 views

The problem

You are given a 0-indexed integer array costs where costs[i] is the cost of hiring the ith worker.

You are also given two integers k and candidates. We want to hire exactly k workers according to the following rules:

  • You will run k sessions and hire exactly one worker in each session.
  • In each hiring session, choose the worker with the lowest cost from either the first candidates workers or the last candidates workers. Break the tie by the smallest index.
    • For example, if costs = [3,2,7,7,1,2] and candidates = 2, then in the first hiring session, we will choose the 4th worker because they have the lowest cost [3,2,7,7,1,2].
    • In the second hiring session, we will choose 1st worker because they have the same lowest cost as 4th worker but they have the smallest index [3,2,7,7,2]. Please note that the indexing may be changed in the process.
  • If there are fewer than candidates workers remaining, choose the worker with the lowest cost among them. Break the tie by the smallest index.
  • A worker can only be chosen once.

Return the total cost to hire exactly k workers.

Example 1:

Input: costs = [17,12,10,2,7,2,11,20,8], k = 3, candidates = 4
Output: 11
Explanation: We hire 3 workers in total. The total cost is initially 0.
- In the first hiring round we choose the worker from [17,12,10,2,7,2,11,20,8]. The lowest cost is 2, and we break the tie by the smallest index, which is 3. The total cost = 0 + 2 = 2.
- In the second hiring round we choose the worker from [17,12,10,7,2,11,20,8]. The lowest cost is 2 (index 4). The total cost = 2 + 2 = 4.
- In the third hiring round we choose the worker from [17,12,10,7,11,20,8]. The lowest cost is 7 (index 3). The total cost = 4 + 7 = 11. Notice that the worker with index 3 was common in the first and last four workers.
The total hiring cost is 11.

Example 2:

Input: costs = [1,2,4,1], k = 3, candidates = 3
Output: 4
Explanation: We hire 3 workers in total. The total cost is initially 0.
- In the first hiring round we choose the worker from [1,2,4,1]. The lowest cost is 1, and we break the tie by the smallest index, which is 0. The total cost = 0 + 1 = 1. Notice that workers with index 1 and 2 are common in the first and last 3 workers.
- In the second hiring round we choose the worker from [2,4,1]. The lowest cost is 1 (index 2). The total cost = 1 + 1 = 2.
- In the third hiring round there are less than three candidates. We choose the worker from the remaining workers [2,4]. The lowest cost is 2 (index 0). The total cost = 2 + 2 = 4.
The total hiring cost is 4.

Constraints:

  • 1 <= costs.length <= 105
  • 1 <= costs[i] <= 105
  • 1 <= k, candidates <= costs.length

Approach overview

Problem Overview: You are given an array costs where each value represents the cost of hiring a worker. You must hire exactly k workers. At each step, you can only choose from the first candidates workers or the last candidates workers that have not yet been hired. The goal is to minimize the total hiring cost while following this rule.

Approach 1: Min-Heap Simulation (O((k + candidates) log candidates) time, O(candidates) space)

This approach simulates the hiring process using a heap (priority queue). Maintain two candidate pools: one from the left side and one from the right side of the array. Push their costs into a min-heap along with their indices. Each time you hire a worker, pop the smallest cost from the heap and add it to the total. Then expand the same side (left or right) by pushing the next available worker into the heap. The heap always gives the cheapest valid worker while dynamically maintaining the hiring window. This approach works well because the heap guarantees efficient retrieval of the minimum cost worker during each of the k hiring steps.

Approach 2: Two Pointers with Sorted Segments (O(n log n) time, O(n) space)

This method uses two pointers to track the active candidate windows from both ends of the array. First build sorted segments for the first and last candidate pools so the cheapest worker from either side can be selected quickly. After hiring a worker from one side, advance the corresponding pointer and insert the next worker into the sorted structure. The process repeats until k workers are hired. The idea relies on maintaining ordered candidate pools while the pointers gradually move inward through the array. Sorting or maintaining ordered containers makes selecting the smallest cost straightforward.

Recommended for interviews: The min-heap simulation is the approach most interviewers expect. It models the hiring rule directly and demonstrates strong understanding of priority queues and simulation. Explaining the window expansion and how the heap always tracks the cheapest available candidate shows solid algorithmic reasoning. The two-pointer sorted approach also works but is typically less intuitive and involves heavier preprocessing.

Approach 1: Min-Heap Approach

In this approach, we use a min-heap to keep track of the candidate workers with the lowest costs. By maintaining a collection of candidate workers from both ends of the list, the algorithm efficiently selects and removes the minimum worker for each session. This helps follow the hierarchical hiring order by prioritizing the smallest cost and index.

import heapq

def total_cost(costs, k, candidates):
    left_candidates = [(cost, i) for i, cost in enumerate(costs[:candidates])]
    right_candidates = [(cost, i) for i, cost in enumerate(costs[-candidates:], start=len(costs)-candidates)]
    
    heapq.heapify(left_candidates)
    heapq.heapify(right_candidates)

    total_cost = 0
    hired_workers = set()

    for _ in range(k):
        while left_candidates and left_candidates[0][1] in hired_workers:
            heapq.heappop(left_candidates)
        while right_candidates and right_candidates[0][1] in hired_workers:
            heapq.heappop(right_candidates)

        if (left_candidates and (not right_candidates or left_candidates[0][0] < right_candidates[0][0] or
                                 (left_candidates[0][0] == right_candidates[0][0] and left_candidates[0][1] <= right_candidates[0][1]))):
            cost, index = heapq.heappop(left_candidates)
        else:
            cost, index = heapq.heappop(right_candidates)

        total_cost += cost
        hired_workers.add(index)

    return total_cost

# Example usage:
print(total_cost([17,12,10,2,7,2,11,20,8], 3, 4))
print(total_cost([1,2,4,1], 3, 3))
function totalCost(costs, k, candidates) {
    let minHeap = new MinHeap();
    let left = [...costs.slice(0, candidates)].map((cost, i) => [cost, i]);
    let right = [...costs.slice(-candidates)].map((cost, i) => [cost, costs.length - candidates + i]);

    left.forEach(worker => minHeap.insert(worker));
    right.forEach(worker => minHeap.insert(worker));

    let totalCost = 0;
    let hired = new Set();

    while (k > 0 && !minHeap.isEmpty()) {
        let [cost, index] = minHeap.extractMin();
        if (hired.has(index)) continue;
        totalCost += cost;
        hired.add(index);
        k--;
    }

    return totalCost;
}

class MinHeap {
    constructor() {
        this.heap = [];
    }

    insert(value) {
        this.heap.push(value);
        this.bubbleUp();
    }

    bubbleUp() {
        let index = this.heap.length - 1;
        const last = this.heap[index];
        while (index > 0) {
            let parentIndex = Math.floor((index - 1) / 2);
            if (this.heap[parentIndex][0] <= last[0]) break;
            this.heap[index] = this.heap[parentIndex];
            index = parentIndex;
        }
        this.heap[index] = last;
    }

    extractMin() {
        const min = this.heap[0];
        const end = this.heap.pop();
        if (this.heap.length) {
            this.heap[0] = end;
            this.sinkDown();
        }
        return min;
    }

    sinkDown() {
        let index = 0;
        const length = this.heap.length;
        const element = this.heap[index];

        while (true) {
            let leftChildIndex = 2 * index + 1;
            let rightChildIndex = 2 * index + 2;
            let leftChild, rightChild;
            let swap = null;

            if (leftChildIndex < length) {
                leftChild = this.heap[leftChildIndex];
                if (leftChild[0] < element[0]) swap = leftChildIndex;
            }

            if (rightChildIndex < length) {
                rightChild = this.heap[rightChildIndex];
                if (
                    (swap === null && rightChild[0] < element[0]) ||
                    (swap !== null && rightChild[0] < leftChild[0])
                ) swap = rightChildIndex;
            }

            if (swap === null) break;

            this.heap[index] = this.heap[swap];
            index = swap;
        }
        this.heap[index] = element;
    }

    isEmpty() {
        return this.heap.length === 0;
    }
}

// Example usage:
console.log(totalCost([17,12,10,2,7,2,11,20,8], 3, 4));
console.log(totalCost([1,2,4,1], 3, 3));

The Python solution uses two heaps to maintain the workers with the lowest costs from both the beginning and the end of the list. By popping the minimum cost worker in each session, it ensures the optimal choice based on cost and then index if there's a tie. The workers are marked as hired so they are not reconsidered in subsequent rounds.

Complexity

Time Complexity: O(k * log(candidates)), where k is the number of workers to hire and candidates the number from both ends considered.
Space Complexity: O(candidates) for maintaining the two heaps.

Try this approach in the editor

Approach 2: Two Pointers with Sorted Segments

This approach involves sorting segments of the array and using two pointers to dynamically track the smallest available candidate from the start and end. By maintaining sorted sections, it allows for efficient extraction by moving pointers closer as sessions proceed.

import java.util.Arrays;

public class TotalCost {
    public static int totalCost(int[] costs, int k, int candidates) {
        int[] left = Arrays.copyOfRange(costs, 0, candidates);
        int[] right = Arrays.copyOfRange(costs, costs.length - candidates, costs.length);

        Arrays.sort(left);
        Arrays.sort(right);

        int totalCost = 0;
        int l_ptr = 0, r_ptr = 0;

        for (int i = 0; i < k; i++) {
            if (l_ptr < candidates && (r_ptr >= candidates || left[l_ptr] <= right[r_ptr])) {
                totalCost += left[l_ptr];
                l_ptr++;
            } else {
                totalCost += right[r_ptr];
                r_ptr++;
            }
        }
        return totalCost;
    }

    public static void main(String[] args) {
        int[] costs = {17, 12, 10, 2, 7, 2, 11, 20, 8};
        System.out.println(totalCost(costs, 3, 4));

        int[] costs2 = {1, 2, 4, 1};
        System.out.println(totalCost(costs2, 3, 3));
    }
}
#include <vector>
#include <algorithm>
using namespace std;

int totalCost(vector<int>& costs, int k, int candidates) {
    vector<pair<int, int>> left(costs.begin(), costs.begin() + candidates);
    vector<pair<int, int>> right(costs.end() - candidates, costs.end());

    sort(left.begin(), left.end());
    sort(right.begin(), right.end());

    int totalCost = 0;
    int l_ptr = 0, r_ptr = 0;

    for (int i = 0; i < k; ++i) {
        if (l_ptr < candidates && (r_ptr >= candidates || left[l_ptr].first <= right[r_ptr].first)) {
            totalCost += left[l_ptr].first;
            l_ptr++;
        } else {
            totalCost += right[r_ptr].first;
            r_ptr++;
        }
    }
    return totalCost;
}

// Example usage:
// vector<int> costs = {17,12,10,2,7,2,11,20,8};
// cout << totalCost(costs, 3, 4);

Java's implementation sorts both sides of potential workers and uses a pointer comparison method to decide the sequence of hiring decisions. As it hires, it adds the selected worker to the total cost after each session.

Complexity

Time Complexity: O(n log candidates) due to sorting.
Space Complexity: O(candidates), requiring storage for both segments.

Try this approach in the editor

Approach 3: Priority Queue (Min Heap)

First, we check if candidates times 2 is greater than or equal to n. If it is, we directly return the sum of the costs of the first k smallest workers.

Otherwise, we use a min heap pq to maintain the costs of the first candidates workers and the last candidates workers.

We first add the costs and corresponding indices of the first candidates workers to the min heap pq, and then add the costs and corresponding indices of the last candidates workers to the min heap pq. We use two pointers l and r to point to the indices of the front and back candidates, initially l = candidates, r = n - candidates - 1.

Then we perform k iterations, each time taking the worker with the smallest cost from the min heap pq and adding its cost to the answer. If l > r, it means that all the front and back candidates have been selected, and we skip directly. Otherwise, if the index of the current worker is less than l, it means it is a worker from the front, we add the cost and index of the l-th worker to the min heap pq, and then increment l; otherwise, we add the cost and index of the r-th worker to the min heap pq, and then decrement r.

After the loop ends, we return the answer.

The time complexity is O(n times log n), and the space complexity is O(n). Where n is the length of the array costs.

function totalCost(costs: number[], k: number, candidates: number): number {
    const n = costs.length;
    if (candidates * 2 >= n) {
        costs.sort((a, b) => a - b);
        return costs.slice(0, k).reduce((acc, x) => acc + x, 0);
    }
    const pq = new PriorityQueue<number[]>((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]));
    for (let i = 0; i < candidates; ++i) {
        pq.enqueue([costs[i], i]);
        pq.enqueue([costs[n - i - 1], n - i - 1]);
    }
    let [l, r] = [candidates, n - candidates - 1];
    let ans = 0;
    while (k--) {
        const [cost, i] = pq.dequeue()!;
        ans += cost;
        if (l > r) {
            continue;
        }
        if (i < l) {
            pq.enqueue([costs[l], l++]);
        } else {
            pq.enqueue([costs[r], r--]);
        }
    }
    return ans;
}
func totalCost(costs []int, k int, candidates int) (ans int64) {
	n := len(costs)
	if candidates*2 > n {
		sort.Ints(costs)
		for _, x := range costs[:k] {
			ans += int64(x)
		}
		return
	}
	pq := hp{}
	for i, x := range costs[:candidates] {
		heap.Push(&pq, pair{x, i})
		heap.Push(&pq, pair{costs[n-i-1], n - i - 1})
	}
	l, r := candidates, n-candidates-1
	for ; k > 0; k-- {
		p := heap.Pop(&pq).(pair)
		ans += int64(p.cost)
		if l > r {
			continue
		}
		if p.i < l {
			heap.Push(&pq, pair{costs[l], l})
			l++
		} else {
			heap.Push(&pq, pair{costs[r], r})
			r--
		}
	}
	return
}

type pair struct{ cost, i int }
type hp []pair

func (h hp) Len() int { return len(h) }
func (h hp) Less(i, j int) bool {
	return h[i].cost < h[j].cost || (h[i].cost == h[j].cost && h[i].i < h[j].i)
}
func (h hp) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *hp) Push(v any)   { *h = append(*h, v.(pair)) }
func (h *hp) Pop() any     { a := *h; v := a[len(a)-1]; *h = a[:len(a)-1]; return v }
Try this approach in the editor

Complexity comparison

ApproachComplexity
Min-Heap Approach

Time Complexity: O(k * log(candidates)), where k is the number of workers to hire and candidates the number from both ends considered.
Space Complexity: O(candidates) for maintaining the two heaps.

Two Pointers with Sorted Segments

Time Complexity: O(n log candidates) due to sorting.
Space Complexity: O(candidates), requiring storage for both segments.

Priority Queue (Min Heap)–

Complexity analysis

ApproachTimeSpaceWhen to Use
Min-Heap SimulationO((k + candidates) log candidates)O(candidates)General case. Best balance of performance and simplicity when repeatedly selecting the minimum cost worker.
Two Pointers with Sorted SegmentsO(n log n)O(n)Useful when you prefer maintaining ordered candidate pools with pointer expansion from both ends.

Frequently asked questions

Is Total Cost to Hire K Workers easy or hard?

Total Cost to Hire K Workers is categorized as a Medium problem. The difficulty comes from managing two candidate windows and dynamically updating them while always selecting the minimum cost worker using a heap.

How to solve Total Cost to Hire K Workers in optimal time?

Use a min-heap to track the cheapest worker among the current left and right candidate pools. Initialize the heap with the first and last 'candidates' workers. After hiring a worker, push the next available worker from that side into the heap. Repeat the process k times to accumulate the minimum total cost.

What is the best approach for Total Cost to Hire K Workers?

The min-heap (priority queue) simulation is the most efficient and commonly used approach. Maintain two candidate pools from the start and end of the array and push their costs into a min-heap. Each hiring step pops the smallest cost and adds a new candidate from the same side. The complexity is O((k + candidates) log candidates) with O(candidates) space.

Is Total Cost to Hire K Workers asked at Google/Amazon/Meta?

Heap-based selection and window simulation problems like this frequently appear in interviews at companies such as Amazon, Google, and Meta. They test understanding of priority queues, greedy decision making, and efficient handling of dynamic candidate sets.

What data structure is used in Total Cost to Hire K Workers?

The primary data structure is a min-heap (priority queue). It efficiently retrieves the lowest cost worker among the current candidates. Two pointers are also used to track the next available workers from the left and right ends of the array.

What is the time complexity of Total Cost to Hire K Workers?

The optimal heap-based solution runs in O((k + candidates) log candidates) time because each hiring operation involves a heap push or pop. The space complexity is O(candidates) for storing the active candidate pool. A sorting-based alternative may take O(n log n) time.

Total Cost to Hire K Workers Python or Java solution approach?

Both Python and Java implementations typically use a priority queue (heap). Python uses the built-in heapq module, while Java uses PriorityQueue. Each step extracts the minimum cost worker and pushes the next candidate from the corresponding side.

Comments

Now write it yourselfClose this page and solve Total Cost to Hire K Workers in the editor, without looking.
Practise Total Cost to Hire K Workers