diff --git a/content/posts/leetcode.md b/content/posts/leetcode.md index f060760..c789000 100644 --- a/content/posts/leetcode.md +++ b/content/posts/leetcode.md @@ -7486,3 +7486,40 @@ func findMaximizedCapital(k int, w int, profits []int, capital []int) int { ### 总结 go中最大堆可以使用容器类heap来实现, 只要实现了heap接口的所有方法, 就可以直接使用这个堆了. + +## day111 2024-06-16 + +### 330. Patching Array + +Given a sorted integer array nums and an integer n, add/patch elements to the array such that any number in the range [1, n] inclusive can be formed by the sum of some elements in the array. + +Return the minimum number of patches required. + +![0616NgRLjhl1dyd6](https://testingcf.jsdelivr.net/gh/game-loader/picbase@master/uPic/0616NgRLjhl1dyd6.png) + +### 题解 + +本题是一道难题, 难点在于根据题目题意, 如何确定某个数组中数的和能够覆盖的数字范围. 按照我们一贯使用的思考方式, 先考虑一下简单情况, 若只有一个数字1, 则能覆盖的数字只有`1`, 添加上一个数字2, 则能覆盖的数字有`1,2,1+2`. 如果在1,2基础上再添加一个数字3, 则能覆盖的数字有`1,2,1+2,3,1+3,2+3,1+2+3`. 则由这几个简单例子可以发现, 如果之前能够覆盖的数字为集合{x}, 则加上一个数字r后能覆盖的数字为集合 $x \cup (x + r)$ . 若之前能够覆盖的为一个连续的区间\[x,x+k\],则加上数字r后能够覆盖的区间为 $ [x,x+k] \cup [x+r, x+k+r]$. 则此时想到可以用贪心算法, 如果已经覆盖了\[x, x+k\], 则只需要让x+r = x+k+1, 即新增加的数恰好可以使得新覆盖区间的开头为已经覆盖区间的末尾. 就能得到\[x,x+k+r]的新覆盖区间. 如果r比这种情况小, 那么新覆盖的区间没有我们当前得到的区间大. 如果比这种情况大, 则x+r和x+k之间会有几个数字没有覆盖上, 还需要再用一个新的数覆盖一次, 显然很难使得添加数字的个数最小. + +将这个思路在代码中实现, 初始化一个数字表示当前覆盖的区间最大值sum, 遍历数组, 设x为nums\[i\], 判断当前sum是否大于nums\[i\](即已经覆盖的区间是否包含当前这个数组中的数字). 如果小于, 则添加一个数字sum+1 **_前面分析中的x+k+1_** (因为题目只要求添加的数字的最小个数,因此不需要真的添加到数组中, 只需扩大可行区间的范围即可), 将区间最大值扩展为sum+sum+1 **_前面分析中的x+k+r_** , 并将添加数字的个数加一. 再次判断与x的关系. 如此反复直到覆盖的区间包含x为止, 继续向下遍历. 遍历完成后, 判断当前区间是否已经可以覆盖n, 如果不能, 则按照之前的方法继续扩展区间直到能覆盖n为止. + +### 代码 + +```go +func minPatches(nums []int, n int) int { + midsum := 0 + result := 0 + for _,value := range nums{ + for midsum < value-1 && midsum < n{ + result++ + midsum += midsum + 1 + } + midsum += value + } + for midsum < n{ + result++ + midsum += midsum + 1 + } + return result +} +```