【LeetCode 1833】雪糕的最大数量

15 篇文章 0 订阅
/*
难度:中等
夏日炎炎,小男孩Tony想买一些雪糕消消暑。
商店中新到n支雪糕,用长度为n的数组costs表示雪糕的定价,其中costs[i]表示第i支雪糕的现金价格。
Tony一共有coins现金可以用于消费,他想要买尽可能多的雪糕。
请计算Tony可以买到的雪糕的最大数量。
Tony可以按任意顺序购买雪糕。

示例:
输入:costs=[1,3,2,4,1], coins=7
输出:4

示例:
输入:costs=[10,6,8,7,7,8], coins=5
输出:0

示例:
输入:costs=[1,6,3,1,2,5], coins=20
输出:6

提示:
costs.length == n
1 <= n <= 10^5
1 <= costs[i] <= 10^5
1 <= coins <= 10^8
*/ 
extension Daily { 
	static func test_leetcode1833() {
		let cases = [
			([1,3,2,4,1], 7),
			([10,6,8,7,7,8], 5),
			([1,6,3,1,2,5], 20)
		]
		for (costs, coins) in cases {
//			let res = Daily.leetcode1833(costs: costs, coins: coins)
			let res = Daily.leetcode1833(costs: costs, coins: coins)
//			print("最终结果 \(res)")
		}
		
	}
	//1 用map计数后再排序,可以减少重复价格雪糕的排序
	//还有一种类似的方法: 因为1<=costs[i]<=10^5,所以可以直接统计从1到10^5出现的次数,而不需要用map,效率更高
	static func leetcode1833(costs: [Int], coins:Int) -> Int {
		if costs.count < 1 || coins < 1 {
			return 0
		}
		
		var map: [Int:Int] = [Int:Int]() 
		for acost in costs {
			map[acost] = (map[acost] ?? 0) + 1
		}
		let sorted = map.sorted{ $0.key < $1.key}
		
//		print("sorted: \(sorted)")
		var sum = 0
		var total = 0
		var rest = coins
		for idx in 0..<sorted.count {
			let key = sorted[idx].key
			if rest < key {
				break
			}
			let canby = rest / key
			let available = sorted[idx].value
			if available > canby {
				total += canby
				sum += canby*key
				break
			}
			let xcost =  available * key
			total += available
			sum += xcost
			rest -= xcost
		}
//		print("coins消耗:\(sum), 能买 \(total) 支雪糕 \n")
		return total
	}
	
	//2 将costs从小到大排序,然后累加并与coins比较;缺点是排序会比较耗时
	static func leetcode1833_2(costs: [Int], coins:Int) -> Int {
		if costs.count < 1 || coins < 1 {
			return 0
		}
		
		let sorted = costs.sorted()
//		print("sorted: \(sorted)")
		var sum = 0
		var total = 0
		for idx in 0..<sorted.count {
			if sum + sorted[idx] <= coins {
				sum += sorted[idx]
				total += 1
			}
			else {
				break
			}
		}
//		print("coins消耗:\(sum), 能买 \(total) 支雪糕 \n")
		return total
	}
	//3 动态规划,但是如果map较大,则此方法不适用
	static func leetcode1833_3(costs: [Int], coins:Int) -> Int {
		if costs.count < 1 || coins < 1 {
			return 0
		}
		
		let cols = coins + 1
		let rows = costs.count + 1
		var map = Array(repeating: 0, count: rows * cols );
		
		for row in 1..<rows {
			let current = costs[row-1]
			for col in 1..<cols {
				let idx = row*cols + col
				let topidx = idx - cols
				if current > col  {
					map[idx] = map[topidx]
				}
				else if current == col  {
					if map[topidx] < 1 {
						map[idx] = 1
					}
				}
				else {
					let include = map[row*cols + col - current - cols] + 1
					if include > map[topidx] {
						map[idx] = include
					}
				}
			}
		}
		showMap(map: map, options: costs, rows: rows, cols: cols)
		print(" 能买 \(map[rows*cols - 1]) 支雪糕 \n")
//		print("coins消耗:\(sum), 能买 \(total) 支雪糕 \n")
		return map[rows*cols - 1]
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值