2023-05-18:有 n 名工人。 給定兩個數(shù)組 quality 和 wage ,
其中,quality[i] 表示第 i 名工人的工作質(zhì)量,其最低期望工資為 wage[i] 。
現(xiàn)在我們想雇傭 k 名工人組成一個工資組。在雇傭 一組 k 名工人時,
我們必須按照下述規(guī)則向他們支付工資:
對工資組中的每名工人,應當按其工作質(zhì)量與同組其他工人的工作質(zhì)量的比例來支付工資。
工資組中的每名工人至少應當?shù)玫剿麄兊淖畹推谕べY。
給定整數(shù) k ,返回 組成滿足上述條件的付費群體所需的最小金額。
輸入: quality = [10,20,5], wage = [70,50,30], k = 2。
輸出: 105.00000。
答案2023-05-18:
解題步驟:
1.構(gòu)造 Employee 結(jié)構(gòu)體,存儲每個員工的工作質(zhì)量和垃圾系數(shù)(wage / quality)。
2.按照垃圾系數(shù)從小到大對所有員工進行排序。
3.維護一個大小為 k 的小根堆,表示當前最低期望工資組中的 k 名工人的工作質(zhì)量。
4.遍歷所有員工,如果堆未滿,則將該員工加入堆中并更新最低期望工資。如果堆已滿,則檢查當前員工能否替換堆頂元素,如果可以,則彈出堆頂元素并將當前員工入堆,更新最低期望工資。
5.最終返回最低期望工資即可。
注意事項:
使用 golang 內(nèi)置的 container/heap 庫來實現(xiàn)小根堆。
在比較垃圾系數(shù)大小時,需要使用小于等于號,因為可能存在兩個員工的垃圾系數(shù)完全相等的情況。
時間復雜度:排序所需的時間為 O(nlogn),遍歷員工數(shù)組時每個員工會入堆一次,出堆一次,即共進行了 2n 次操作,而小根堆的插入和彈出操作時間復雜度均為 O(logk),因此總時間復雜度為 O(nlogn + nlogk)。
空間復雜度:除給定數(shù)組外,我們還需要構(gòu)造 Employee 結(jié)構(gòu)體,以及維護大小為 k 的小根堆,因此需要額外使用 O(n) 空間來存儲結(jié)構(gòu)體數(shù)組,并且在堆滿時可能需要對堆進行調(diào)整,最多需要 O(k) 的額外空間。因此總空間復雜度為 O(n + k)。
go完整代碼如下:
package main
import (
"container/heap"
"fmt"
"sort"
)
type Employee struct {
RubbishDegree float64
Quality int
}
func NewEmployee(w, q int) Employee {
return Employee{RubbishDegree: float64(w) / float64(q), Quality: q}
}
type EmployeeHeap []int
func (h EmployeeHeap) Len() int { return len(h) }
func (h EmployeeHeap) Less(i, j int) bool { return h[i] > h[j] }
func (h EmployeeHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *EmployeeHeap) Push(x interface{}) { *h = append(*h, x.(int)) }
func (h *EmployeeHeap) Pop() interface{} {
n := len(*h)
x := (*h)[n-1]
*h = (*h)[:n-1]
return x
}
func min(a, b float64) float64 {
if a < b {
return a
}
return b
}
func mincostToHireWorkers(quality []int, wage []int, k int) float64 {
n := len(quality)
employees := make([]Employee, n)
for i := range quality {
employees[i] = NewEmployee(wage[i], quality[i])
}
sort.Slice(employees, func(i, j int) bool {
return employees[i].RubbishDegree <= employees[j].RubbishDegree
})
minTops := &EmployeeHeap{}
heap.Init(minTops)
ans, qualitySum := 1e9, 0
for i := 0; i < n; i++ {
curQuality := employees[i].Quality
if minTops.Len() < k { // 堆沒滿
qualitySum += curQuality
heap.Push(minTops, curQuality)
if minTops.Len() == k {
ans = min(ans, float64(qualitySum)*employees[i].RubbishDegree)
}
} else { // 來到當前員工的時候,堆是滿的!
// 當前員工的能力,可以把堆頂干掉,自己進來!
if top := (*minTops)[0]; top > curQuality {
heap.Pop(minTops)
qualitySum += curQuality - top
heap.Push(minTops, curQuality)
ans = min(ans, float64(qualitySum)*employees[i].RubbishDegree)
}
}
}
return ans
}
func main() {
quality := []int{10, 20, 5}
wage := []int{70, 50, 30}
k := 2
result := mincostToHireWorkers(quality, wage, k)
fmt.Println(result)
}
[圖片上傳失敗...(image-827269-1684419248985)]
rust完整代碼如下:
struct Employee {
rubbish_degree: f64,
quality: i32,
}
impl Employee {
fn new(w: i32, q: i32) -> Self {
let rubbish_degree = w as f64 / q as f64;
Self {
rubbish_degree,
quality: q,
}
}
}
fn mincost_to_hire_workers(quality: Vec<i32>, wage: Vec<i32>, k: i32) -> f64 {
let n = quality.len();
let mut employees = Vec::with_capacity(n);
for i in 0..n {
employees.push(Employee::new(wage[i], quality[i]));
}
// 只根據(jù)垃圾指數(shù)排序
// 要價 / 能力
employees.sort_by(|a, b| a.rubbish_degree.partial_cmp(&b.rubbish_degree).unwrap());
// 請維持力量最小的前K個力量
// 大根堆!門檻堆!
let mut min_tops = std::collections::BinaryHeap::new();
let mut ans = std::f64::MAX;
let mut quality_sum = 0;
for i in 0..n {
// i : 依次所有員工的下標
// quality_sum : 進入堆的力量總和!
// cur_quality當前能力
let cur_quality = employees[i].quality;
if min_tops.len() < k as usize {
// 堆沒滿
quality_sum += cur_quality;
min_tops.push(cur_quality);
if min_tops.len() == k as usize {
ans = ans.min(quality_sum as f64 * employees[i].rubbish_degree);
}
} else {
// 來到當前員工的時候,堆是滿的!
// 當前員工的能力,可以把堆頂干掉,自己進來!
if let Some(top) = min_tops.peek() {
if *top > cur_quality {
quality_sum += cur_quality - min_tops.pop().unwrap();
min_tops.push(cur_quality);
ans = ans.min(quality_sum as f64 * employees[i].rubbish_degree);
}
}
}
}
ans
}
fn main() {
let quality = vec![10, 20, 5];
let wage = vec![70, 50, 30];
let k = 2;
let result = mincost_to_hire_workers(quality, wage, k);
println!("{}", result);
}
[圖片上傳失敗...(image-b91595-1684419248986)]
c完整代碼如下:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
typedef struct Employee {
double rubbishDegree;
int quality;
} Employee;
int cmp(const void* a, const void* b) {
Employee* pa = (Employee*)a;
Employee* pb = (Employee*)b;
if (pa->rubbishDegree < pb->rubbishDegree) {
return -1;
}
else if (pa->rubbishDegree > pb->rubbishDegree) {
return 1;
}
else {
return 0;
}
}
double mincostToHireWorkers(int* quality, int qualitySize, int* wage, int wageSize, int k) {
int n = qualitySize;
Employee* employees = (Employee*)malloc(n * sizeof(Employee));
for (int i = 0; i < n; i++) {
employees[i].quality = quality[i];
employees[i].rubbishDegree = (double)wage[i] / (double)quality[i];
}
qsort(employees, n, sizeof(Employee), cmp);
int* minTops = (int*)malloc(k * sizeof(int));
int topIndex = -1;
double ans = INT_MAX;
int qualitySum = 0;
for (int i = 0; i < n; i++) {
int curQuality = employees[i].quality;
if (topIndex < k - 1) {
qualitySum += curQuality;
minTops[++topIndex] = curQuality;
if (topIndex == k - 1) {
ans = qualitySum * employees[i].rubbishDegree;
}
}
else {
if (minTops[0] > curQuality) {
qualitySum += curQuality - minTops[0];
minTops[0] = curQuality;
ans = qualitySum * employees[i].rubbishDegree;
// 調(diào)整,使堆繼續(xù)保持最小堆的性質(zhì)
for (int j = 0; j < k - 1; j++) {
if (minTops[j] > minTops[j + 1]) {
int tmp = minTops[j];
minTops[j] = minTops[j + 1];
minTops[j + 1] = tmp;
}
else {
break;
}
}
}
}
}
free(employees);
free(minTops);
return ans;
}
int main() {
int quality[] = { 10,20,5 };
int wage[] = { 70,50,30 };
int k = 2;
double result = mincostToHireWorkers(quality, sizeof(quality) / sizeof(int), wage, sizeof(wage) / sizeof(int), k);
printf("%lf\n", result);
return 0;
}
[圖片上傳失敗...(image-e54c-1684419248986)]
c++完整代碼如下:
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
#include <limits>
using namespace std;
struct Employee {
double rubbishDegree;
int quality;
Employee() = default;
Employee(int w, int q) : rubbishDegree(static_cast<double>(w) / static_cast<double>(q)), quality(q) {}
bool operator<(const Employee& other) const {
return rubbishDegree < other.rubbishDegree;
}
};
double mincostToHireWorkers(vector<int>& quality, vector<int>& wage, int k) {
int n = quality.size();
vector<Employee> employees(n);
for (int i = 0; i < n; i++) {
employees[i] = Employee(wage[i], quality[i]);
}
// 只根據(jù)垃圾指數(shù)排序
sort(employees.begin(), employees.end());
// 請維持力量最小的前K個力量
// 大根堆!門檻堆!
priority_queue<int> minTops;
double ans = numeric_limits<double>::max();
for (int i = 0, qualitySum = 0; i < n; i++) {
// i : 依次所有員工的下標
// qualitySum : 進入堆的力量總和!
// curQuality當前能力
int curQuality = employees[i].quality;
if (minTops.size() < k) { // 堆沒滿
qualitySum += curQuality;
minTops.push(curQuality);
if (minTops.size() == k) {
ans = min(ans, qualitySum * employees[i].rubbishDegree);
}
}
else { // 來到當前員工的時候,堆是滿的!
// 當前員工的能力,可以把堆頂干掉,自己進來!
if (minTops.top() > curQuality) {
// qualitySum -= minTops.top();
// qualitySum += curQuality;
// minTops.pop();
// minTops.push(curQuality);
qualitySum += curQuality - minTops.top();
minTops.pop();
minTops.push(curQuality);
ans = min(ans, qualitySum * employees[i].rubbishDegree);
}
}
}
return ans;
}
int main() {
vector<int> quality = { 10, 20, 5 };
vector<int> wage = { 70, 50, 30 };
int k = 2;
double result = mincostToHireWorkers(quality, wage, k);
cout << result << endl; // 105
return 0;
}
[圖片上傳失敗...(image-2e16a7-1684419248986)]