diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index 831641a..ed0ee79 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -7525,7 +7525,8 @@ func minPatches(nums []int, n int) int { ``` ## day112 2024-06-17 -### 633. Sum of Square Numbers + +### 633. Sum of Square Numbers Given a non-negative integer c, decide whether there're two integers a and b such that a2 + b2 = c. @@ -7533,10 +7534,11 @@ Given a non-negative integer c, decide whether there're two integers a and b suc ### 题解 -本题计算出c的平方根, 用两个变量low和high分别标记0和c的平方根(取下整), 计算两变量的平方和, 若比c大则减小high, 否则增大low, 直到得到平方和为c或者low=high为止. +本题计算出c的平方根, 用两个变量low和high分别标记0和c的平方根(取下整), 计算两变量的平方和, 若比c大则减小high, 否则增大low, 直到得到平方和为c或者low=high为止. ### 代码 -```go + +```go func judgeSquareSum(c int) bool { high := int(math.Sqrt(float64(c))) low := 0 @@ -7554,8 +7556,127 @@ func judgeSquareSum(c int) bool { ``` ### 总结 + 本题还有一些有趣的相关数学知识, 费马两平方和定理和两数平方和定理, 前者说明了一个奇素数何时能被写为两平方数之和. 满足条件的奇素数也被称为毕达哥拉斯质数, 后者给出了所有大于1的整数在什么情况下能被写为两平方数之和. 是前者的推广. 可参考 -[Fermat's theorem on sums of two squares](https://en.wikipedia.org/wiki/Fermat%27s_theorem_on_sums_of_two_squares) +[Fermat's theorem on sums of two squares](https://en.wikipedia.org/wiki/Fermat%27s_theorem_on_sums_of_two_squares) -[Sum of two squares theorem](https://en.wikipedia.org/wiki/Sum_of_two_squares_theorem) +[Sum of two squares theorem](https://en.wikipedia.org/wiki/Sum_of_two_squares_theorem) + +## day113 2024-06-18 + +### 826. Most Profit Assigning Work + +You have n jobs and m workers. You are given three arrays: difficulty, profit, and worker where: + +difficulty[i] and profit[i] are the difficulty and the profit of the ith job, and +worker[j] is the ability of jth worker (i.e., the jth worker can only complete a job with difficulty at most worker[j]). +Every worker can be assigned at most one job, but one job can be completed multiple times. + +For example, if three workers attempt the same job that pays $1, then the total profit will be $3. If a worker cannot complete any job, their profit is $0. +Return the maximum profit we can achieve after assigning the workers to the jobs. + +![0618rpZxsUIGJ5f6](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0618rpZxsUIGJ5f6.png) + +### 题解 + +本题仍然使用贪心算法, 首先给worker排序, 在排好序后遍历worker数组, 并把当前worker可以做的工作中profit最大的分配给他, 即给结果加上可以做的工作中的最大profit, 这个最大profit可以使用一个变量来保存, 当遍历的下一个worker时, 根据他的工作能力更新可以做的工作中的最大值. 如此反复, 最终得到结果. + +### 代码 + +```go +func maxProfitAssignment(difficulty []int, profit []int, worker []int) int { + sort.Ints(worker) + length := len(profit) + type w_p struct{ + diff int + profit int + } + d_p := make([]w_p, length) + for i,value := range profit{ + d_p[i].diff = difficulty[i] + d_p[i].profit = value + } + sort.Slice(d_p, func(i, j int) bool {return d_p[i].diff < d_p[j].diff}) + + max_pro := 0 + index := 0 + result := 0 + for _, value := range worker{ + for index < length && d_p[index].diff <= value{ + max_pro = max(max_pro, d_p[index].profit) + index++ + } + result += max_pro + } + return result +} +``` + +### 总结 + +为什么排序如此重要, 正如之前的题解中多次提到的, 一个排好序的数组在遍历的时候天然包含了更多信息, 即前面的数字比当前的小, 后面的比当前的大. 使用贪心的重要思想就是, 在当前能获得的结果中取最好的, 那么对于排好序的数组, 前面的必然比当前小, 我只需要依次遍历找到我能拿到的最大值即可. 如果没有排序, 那么我们每次都要将数组整体遍历一遍才能确定我当前能拿到的最大值是多少(后面可能有难度更小但利润更大的任务, 显然我们都想做这种任务). 每次都遍历一遍数组整体是 $n^2$ 的复杂度, 排好序后可以用下标标记之前遍历到哪里了, 只需要遍历一遍数组即可. 是 $nlogn(排序)+n(遍历数组) = O(nlogn) $ 的复杂度. 只有在排好序的数组里标记之前遍历到哪里才有意义, 未排序的数组标记之前遍历到哪里没什么意义(后面既可能有更大的, 也可能有更小的) + +## day114 2024-06-19 + +### 1482. Minimum Number of Days to Make m Bouquets + +You are given an integer array bloomDay, an integer m and an integer k. + +You want to make m bouquets. To make a bouquet, you need to use k adjacent flowers from the garden. + +The garden consists of n flowers, the ith flower will bloom in the bloomDay[i] and then can be used in exactly one bouquet. + +Return the minimum number of days you need to wait to be able to make m bouquets from the garden. If it is impossible to make m bouquets return -1. + +![0619sTVISIXdeV4b](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0619sTVISIXdeV4b.png) + +### 题解 + +不能做出足够的花束的条件是很容易确定的, 只要花园里花的总数比需要的数量小, 则直接返回-1. 否则只要等待足够长的时间, 总能做出足够的花束. 如果等待时间为花盛开时间的最大值, 显然一定满足条件, 若为最小值, 不一定满足条件, 即实际上本题转化为在所有盛开时间中搜索能满足条件的最小值. 对于给定一个时间, 只需要遍历一遍bloomDay数组即可得知其是否满足条件. 这种搜索其实与在一个数组中搜索指定的数没有本质上的区别, 将数组排序后使用二分查找, 对于搜索某一固定数字, 我们采取的方式是如果中间值比目标大, 则将右边界设为中间值, 否则将左边界设为中间值. 如此反复. 而在本题中, 虽然不能直接比较目标值与中间值的相对大小, 但通过使用中间值对bloomDay数组遍历判断是否能做成足够数量的花束(设一个标记变量保存当前连续可使用的花的数量,大于等于k时将当前花束数量加1,最后判断花束数量是否大于等于m)我们可以了解到目标值与中间值的相对大小. 如果此中间值满足题目条件, 那么目标值应该小于等于这个中间值, 否则大于等于这个中间值, 因此回到了最熟悉的二分搜索部分. + +### 代码 + +```go +func minDays(bloomDay []int, m int, k int) int { + if len(bloomDay) < m*k{ + return -1 + } + + left := 1 + right := 0 + for _,value := range bloomDay{ + if value > right{ + right = value + } + } + mid := 0 + begin := 0 + bouquet := 0 + for left < right{ + mid = (left + right) / 2 + begin = 0 + bouquet = 0 + for _,value := range bloomDay{ + if value <= mid{ + begin++ + if begin >= k{ + begin = 0 + bouquet++ + if bouquet >= m{ + break + } + } + }else{ + begin = 0 + } + } + if bouquet >= m{ + right = mid + }else{ + left = mid+1 + } + } + return left +} +```