饭馆菜品选择问题 | 豆包MarsCode AI刷题

65 阅读3分钟

饭馆菜品选择问题

问题描述

小C来到了一家饭馆,这里共有 n 道菜,第 i 道菜的价格为 a_i。其中一些菜中含有蘑菇,s_i 代表第 i 道菜是否含有蘑菇。如果 s_i = '1',那么第 i 道菜含有蘑菇,否则没有。
小C希望点 k 道菜,且希望总价格尽可能低。由于她不喜欢蘑菇,她希望所点的菜中最多只有 m 道菜含有蘑菇。小C想知道在满足条件的情况下能选出的最小总价格是多少。如果无法按照要求选择菜品,则输出-1。

测试样例

样例1

输入:s = "001", a = [10, 20, 30], m = 1, k = 2
输出:30

样例2

输入:s = "111", a = [10, 20, 30], m = 1, k = 2
输出:-1

样例3

输入:s = "0101", a = [5, 15, 10, 20], m = 2, k = 3
输出:30

算法设计

  1. 预处理:首先计算字符串 s 中含有蘑菇的菜品数量 count
  2. 可行性检查:如果菜品总数小于 k 或者即使全部替换掉蘑菇也无法达到 k 元,则提前返回 -1
  3. 排序:为了尽可能少地花费,先对价格列表 a 进行升序排列。
  4. 选择菜品:遍历排序后的价格列表,优先选择不含蘑菇的菜品,直到总价达到 k 或者无法再增加总价为止。

复杂度分析

时间复杂度分析

  1. 初始化

    • 将字符串 s 转换为 []rune,时间复杂度为 (O(n)),其中 (n) 是字符串 s 的长度。
    • 计算含有蘑菇的菜品数量 count,需要遍历字符串 s,时间复杂度为 (O(n))。
  2. 可行性检查

    • 检查 n < kn - count + m < k,这些操作的时间复杂度为 (O(1))。
  3. 排序

    • 使用 sort.Ints(a) 对价格数组 a 进行升序排序。Go 标准库中的 sort.Ints 使用的是快速排序算法(在某些情况下退化为堆排序),其平均时间复杂度为 (O(n \log n))。
  4. 选择菜品

    • 遍历排序后的数组 a,进行选择菜品的操作。最坏情况下需要遍历整个数组,时间复杂度为 (O(n))。

综上所述,总的时间复杂度由排序步骤决定,即 (O(n \log n))。

空间复杂度分析

  1. 字符串转换

    • 将字符串 s 转换为 []rune,空间复杂度为 (O(n))。
  2. 其他变量

    • 除了 ch 之外,其他变量如 count, sum, m, k 等都是常数级别的额外空间,空间复杂度为 (O(1))。
  3. 排序

    • Go 标准库中的 sort.Ints 在原地排序,不需要额外的空间,空间复杂度为 (O(1))。

综上所述,总的空间复杂度为 (O(n))。

代码

package main

import (
	"fmt"
	"sort"
)

func solution(s string, a []int, m int, k int) int64 {
	n := len(a)
	ch := []rune(s)
	count := 0
	for i := 0; i < n; i++ {
		if ch[i] == '1' {
			count++
		}
	}
	if n < k {
		return -1
	}
	if n-count+m < k {
		return -1
	}
	sum := 0
	sort.Ints(a) // 直接使用内置排序函数代替冒泡排序
	for i := 0; i < n; i++ {
		if ch[i] == '1' {
			if m > 0 {
				sum += a[i]
				k--
				m--
				if k == 0 {
					break
				}
				continue
			}
		} else {
			sum += a[i]
			k--
			if k == 0 {
				break
			}
		}
	}
	return int64(sum)
}

测试

func main() {
	fmt.Println(solution("001", []int{10, 20, 30}, 1, 2) == 30)
	fmt.Println(solution("111", []int{10, 20, 30}, 1, 2) == -1)
	fmt.Println(solution("0101", []int{5, 15, 10, 20}, 2, 3) == 30)
}