diff --git a/leetcode/5561.Get-Maximum-in-Generated-Array/5561. Get Maximum in Generated Array.go b/leetcode/1646.Get-Maximum-in-Generated-Array/1646. Get Maximum in Generated Array.go similarity index 100% rename from leetcode/5561.Get-Maximum-in-Generated-Array/5561. Get Maximum in Generated Array.go rename to leetcode/1646.Get-Maximum-in-Generated-Array/1646. Get Maximum in Generated Array.go diff --git a/leetcode/1646.Get-Maximum-in-Generated-Array/1646. Get Maximum in Generated Array_test.go b/leetcode/1646.Get-Maximum-in-Generated-Array/1646. Get Maximum in Generated Array_test.go new file mode 100644 index 00000000..38472190 --- /dev/null +++ b/leetcode/1646.Get-Maximum-in-Generated-Array/1646. Get Maximum in Generated Array_test.go @@ -0,0 +1,62 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question1646 struct { + para1646 + ans1646 +} + +// para 是参数 +// one 代表第一个参数 +type para1646 struct { + n int +} + +// ans 是答案 +// one 代表第一个答案 +type ans1646 struct { + one int +} + +func Test_Problem1646(t *testing.T) { + + qs := []question1646{ + + { + para1646{7}, + ans1646{3}, + }, + + { + para1646{2}, + ans1646{1}, + }, + + { + para1646{3}, + ans1646{2}, + }, + + { + para1646{0}, + ans1646{0}, + }, + + { + para1646{1}, + ans1646{1}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 1646------------------------\n") + + for _, q := range qs { + _, p := q.ans1646, q.para1646 + fmt.Printf("【input】:%v 【output】:%v \n", p, getMaximumGenerated(p.n)) + } + fmt.Printf("\n\n\n") +} diff --git a/leetcode/1646.Get-Maximum-in-Generated-Array/README.md b/leetcode/1646.Get-Maximum-in-Generated-Array/README.md new file mode 100644 index 00000000..a703bba7 --- /dev/null +++ b/leetcode/1646.Get-Maximum-in-Generated-Array/README.md @@ -0,0 +1,96 @@ +# [1646. Get Maximum in Generated Array](https://leetcode.com/problems/get-maximum-in-generated-array/) + + +## 题目 + +You are given an integer `n`. An array `nums` of length `n + 1` is generated in the following way: + +- `nums[0] = 0` +- `nums[1] = 1` +- `nums[2 * i] = nums[i]` when `2 <= 2 * i <= n` +- `nums[2 * i + 1] = nums[i] + nums[i + 1]` when `2 <= 2 * i + 1 <= n` + +Return *****the **maximum** integer in the array* `nums`. + +**Example 1:** + +``` +Input: n = 7 +Output: 3 +Explanation: According to the given rules: + nums[0] = 0 + nums[1] = 1 + nums[(1 * 2) = 2] = nums[1] = 1 + nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2 + nums[(2 * 2) = 4] = nums[2] = 1 + nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3 + nums[(3 * 2) = 6] = nums[3] = 2 + nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3 +Hence, nums = [0,1,1,2,1,3,2,3], and the maximum is 3. + +``` + +**Example 2:** + +``` +Input: n = 2 +Output: 1 +Explanation: According to the given rules, the maximum between nums[0], nums[1], and nums[2] is 1. + +``` + +**Example 3:** + +``` +Input: n = 3 +Output: 2 +Explanation: According to the given rules, the maximum between nums[0], nums[1], nums[2], and nums[3] is 2. + +``` + +**Constraints:** + +- `0 <= n <= 100` + +## 题目大意 + +给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums : + +- nums[0] = 0 +- nums[1] = 1 +- 当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i] +- 当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1] + +返回生成数组 nums 中的 最大值。 + +## 解题思路 + +- 给出一个 n + 1 的数组,并按照生成规则生成这个数组,求出这个数组中的最大值。 +- 简单题,按照题意生成数组,边生成边记录和更新最大值即可。 +- 注意边界条件,当 n 为 0 的时候,数组里面只有一个元素 0 。 + +## 代码 + +```go +package leetcode + +func getMaximumGenerated(n int) int { + if n == 0 { + return 0 + } + nums, max := make([]int, n+1), 0 + nums[0], nums[1] = 0, 1 + for i := 0; i <= n; i++ { + if nums[i] > max { + max = nums[i] + } + if 2*i >= 2 && 2*i <= n { + nums[2*i] = nums[i] + } + if 2*i+1 >= 2 && 2*i+1 <= n { + nums[2*i+1] = nums[i] + nums[i+1] + } + } + return max +} +``` \ No newline at end of file diff --git a/leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique.go b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique.go similarity index 91% rename from leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique.go rename to leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique.go index 39249854..30219660 100644 --- a/leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique.go +++ b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique.go @@ -1,7 +1,6 @@ package leetcode import ( - "fmt" "sort" ) @@ -11,7 +10,6 @@ func minDeletions(s string) int { frequency[s[i]-'a']++ } sort.Sort(sort.Reverse(sort.IntSlice(frequency))) - fmt.Printf("%v\n", frequency) for i := 1; i <= 25; i++ { if frequency[i] == frequency[i-1] && frequency[i] != 0 { res++ diff --git a/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique_test.go b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique_test.go new file mode 100644 index 00000000..3bdc2735 --- /dev/null +++ b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/1647. Minimum Deletions to Make Character Frequencies Unique_test.go @@ -0,0 +1,62 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question1647 struct { + para1647 + ans1647 +} + +// para 是参数 +// one 代表第一个参数 +type para1647 struct { + s string +} + +// ans 是答案 +// one 代表第一个答案 +type ans1647 struct { + one int +} + +func Test_Problem1647(t *testing.T) { + + qs := []question1647{ + + { + para1647{"aab"}, + ans1647{0}, + }, + + { + para1647{"aaabbbcc"}, + ans1647{2}, + }, + + { + para1647{"ceabaacb"}, + ans1647{2}, + }, + + { + para1647{""}, + ans1647{0}, + }, + + { + para1647{"abcabc"}, + ans1647{3}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 1647------------------------\n") + + for _, q := range qs { + _, p := q.ans1647, q.para1647 + fmt.Printf("【input】:%v 【output】:%v \n", p, minDeletions(p.s)) + } + fmt.Printf("\n\n\n") +} diff --git a/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/README.md b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/README.md new file mode 100644 index 00000000..e6b2fff8 --- /dev/null +++ b/leetcode/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique/README.md @@ -0,0 +1,89 @@ +# [1647. Minimum Deletions to Make Character Frequencies Unique](https://leetcode.com/problems/minimum-deletions-to-make-character-frequencies-unique/) + + +## 题目 + +A string `s` is called **good** if there are no two different characters in `s` that have the same **frequency**. + +Given a string `s`, return *the **minimum** number of characters you need to delete to make* `s` ***good**.* + +The **frequency** of a character in a string is the number of times it appears in the string. For example, in the string `"aab"`, the **frequency** of `'a'` is `2`, while the **frequency** of `'b'` is `1`. + +**Example 1:** + +``` +Input: s = "aab" +Output: 0 +Explanation: s is already good. + +``` + +**Example 2:** + +``` +Input: s = "aaabbbcc" +Output: 2 +Explanation: You can delete two 'b's resulting in the good string "aaabcc". +Another way it to delete one 'b' and one 'c' resulting in the good string "aaabbc". +``` + +**Example 3:** + +``` +Input: s = "ceabaacb" +Output: 2 +Explanation: You can delete both 'c's resulting in the good string "eabaab". +Note that we only care about characters that are still in the string at the end (i.e. frequency of 0 is ignored). + +``` + +**Constraints:** + +- `1 <= s.length <= 105` +- `s` contains only lowercase English letters. + +## 题目大意 + +如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。 + +给你一个字符串 s,返回使 s 成为优质字符串需要删除的最小字符数。 + +字符串中字符的 频次 是该字符在字符串中的出现次数。例如,在字符串 "aab" 中,'a' 的频次是 2,而 'b' 的频次是 1 。 + +**提示:** + +- `1 <= s.length <= 105` +- `s` 仅含小写英文字母 + +## 解题思路 + +- 给出一个字符串 s,要求输出使 s 变成“优质字符串”需要删除的最小字符数。“优质字符串”的定义是:字符串 s 中不存在频次相同的两个不同字符。 +- 首先将 26 个字母在字符串中的频次分别统计出来,然后把频次从大到小排列,从频次大的开始,依次调整:例如,假设前一个和后一个频次相等,就把前一个字符删除一个,频次减一,再次排序,如果频次还相等,继续调整,如果频次不同了,游标往后移,继续调整后面的频次。直到所有的频次都不同了,就可以输出最终结果了。 +- 这里需要注意频次为 0 的情况,即字母都被删光了。频次为 0 以后,就不需要再比较了。 + +## 代码 + +```go +package leetcode + +import ( + "sort" +) + +func minDeletions(s string) int { + frequency, res := make([]int, 26), 0 + for i := 0; i < len(s); i++ { + frequency[s[i]-'a']++ + } + sort.Sort(sort.Reverse(sort.IntSlice(frequency))) + for i := 1; i <= 25; i++ { + if frequency[i] == frequency[i-1] && frequency[i] != 0 { + res++ + frequency[i]-- + sort.Sort(sort.Reverse(sort.IntSlice(frequency))) + i-- + } + } + return res +} +``` \ No newline at end of file diff --git a/leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls.go b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls.go similarity index 50% rename from leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls.go rename to leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls.go index 88103a63..677a3699 100644 --- a/leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls.go +++ b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls.go @@ -4,7 +4,55 @@ import ( "container/heap" ) +// 解法一 贪心 + 二分搜索 func maxProfit(inventory []int, orders int) int { + maxItem, thresholdValue, count, res, mod := 0, -1, 0, 0, 1000000007 + for i := 0; i < len(inventory); i++ { + if inventory[i] > maxItem { + maxItem = inventory[i] + } + } + low, high := 0, maxItem + for low <= high { + mid := low + ((high - low) >> 1) + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-mid, 0) + } + if count <= orders { + thresholdValue = mid + high = mid - 1 + } else { + low = mid + 1 + } + count = 0 + } + count = 0 + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-thresholdValue, 0) + } + count = orders - count + for i := 0; i < len(inventory); i++ { + if inventory[i] >= thresholdValue { + if count > 0 { + res += (thresholdValue + inventory[i]) * (inventory[i] - thresholdValue + 1) / 2 + count-- + } else { + res += (thresholdValue + 1 + inventory[i]) * (inventory[i] - thresholdValue) / 2 + } + } + } + return res % mod +} + +func max(a int, b int) int { + if a > b { + return a + } + return b +} + +// 解法二 优先队列,超时! +func maxProfit_(inventory []int, orders int) int { res, mod := 0, 1000000007 q := PriorityQueue{} for i := 0; i < len(inventory); i++ { diff --git a/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls_test.go b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls_test.go new file mode 100644 index 00000000..b81ce0e6 --- /dev/null +++ b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/1648. Sell Diminishing-Valued Colored Balls_test.go @@ -0,0 +1,63 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question1648 struct { + para1648 + ans1648 +} + +// para 是参数 +// one 代表第一个参数 +type para1648 struct { + inventory []int + orders int +} + +// ans 是答案 +// one 代表第一个答案 +type ans1648 struct { + one int +} + +func Test_Problem1648(t *testing.T) { + + qs := []question1648{ + + { + para1648{[]int{2, 3, 3, 4, 5}, 4}, + ans1648{16}, + }, + + { + para1648{[]int{2, 5}, 4}, + ans1648{14}, + }, + + { + para1648{[]int{3, 5}, 6}, + ans1648{19}, + }, + + { + para1648{[]int{2, 8, 4, 10, 6}, 20}, + ans1648{110}, + }, + + { + para1648{[]int{1000000000}, 1000000000}, + ans1648{21}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 1648------------------------\n") + + for _, q := range qs { + _, p := q.ans1648, q.para1648 + fmt.Printf("【input】:%v 【output】:%v \n", p, maxProfit(p.inventory, p.orders)) + } + fmt.Printf("\n\n\n") +} diff --git a/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/README.md b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/README.md new file mode 100644 index 00000000..bddd91b3 --- /dev/null +++ b/leetcode/1648.Sell-Diminishing-Valued-Colored-Balls/README.md @@ -0,0 +1,131 @@ +# [1648. Sell Diminishing-Valued Colored Balls](https://leetcode.com/problems/sell-diminishing-valued-colored-balls/) + + +## 题目 + +You have an `inventory` of different colored balls, and there is a customer that wants `orders` balls of **any** color. + +The customer weirdly values the colored balls. Each colored ball's value is the number of balls **of that color** you currently have in your `inventory`. For example, if you own `6` yellow balls, the customer would pay `6` for the first yellow ball. After the transaction, there are only `5` yellow balls left, so the next yellow ball is then valued at `5` (i.e., the value of the balls decreases as you sell more to the customer). + +You are given an integer array, `inventory`, where `inventory[i]` represents the number of balls of the `ith` color that you initially own. You are also given an integer `orders`, which represents the total number of balls that the customer wants. You can sell the balls **in any order**. + +Return *the **maximum** total value that you can attain after selling* `orders` *colored balls*. As the answer may be too large, return it **modulo** `109 + 7`. + +**Example 1:** + +![https://assets.leetcode.com/uploads/2020/11/05/jj.gif](https://assets.leetcode.com/uploads/2020/11/05/jj.gif) + +``` +Input: inventory = [2,5], orders = 4 +Output: 14 +Explanation: Sell the 1st color 1 time (2) and the 2nd color 3 times (5 + 4 + 3). +The maximum total value is 2 + 5 + 4 + 3 = 14. + +``` + +**Example 2:** + +``` +Input: inventory = [3,5], orders = 6 +Output: 19 +Explanation: Sell the 1st color 2 times (3 + 2) and the 2nd color 4 times (5 + 4 + 3 + 2). +The maximum total value is 3 + 2 + 5 + 4 + 3 + 2 = 19. +``` + +**Example 3:** + +``` +Input: inventory = [2,8,4,10,6], orders = 20 +Output: 110 +``` + +**Example 4:** + +``` +Input: inventory = [1000000000], orders = 1000000000 +Output: 21 +Explanation: Sell the 1st color 1000000000 times for a total value of 500000000500000000. 500000000500000000 modulo 109 + 7 = 21. +``` + +**Constraints:** + +- `1 <= inventory.length <= 10^5` +- `1 <= inventory[i] <= 10^9` +- `1 <= orders <= min(sum(inventory[i]), 10^9)` + +## 题目大意 + +你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的) + +给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。 + +提示: + +- 1 <= inventory.length <= 10^5 +- 1 <= inventory[i] <= 10^9 +- 1 <= orders <= min(sum(inventory[i]), 10^9) + +## 解题思路 + +- 给出一个 `inventory` 数组和 `orders` 次操作,要求输出数组中前 `orders` 大个元素累加和。需要注意的是,每累加一个元素 `inventory[i]`,这个元素都会减一,下次再累加的时候,需要选取更新以后的数组的最大值。 +- 拿到这个题目以后很容易想到优先队列,建立大根堆以后,`pop` 出当前最大值 `maxItem`,累加,以后把 `maxItem` 减一再 `push` 回去。循环执行 `orders` 次以后即是最终结果。题目是这个意思,但是我们不能这么写代码,因为题目条件里面给出了 `orders` 的数据大小。orders 最大为 10^9。按照优先队列的这个方法一定会超时,时间复杂度为 O(orders⋅logn)。那就换一个思路。优先队列这个思路中,重复操作了 `orders` 次,其实在这些操作中,有一些是没有必要的废操作。这些大量的“废”操作导致了超时。试想,在 `orders` 次操作中,能否合并 `n` 个 `pop` 操作,一口气先 `pop` 掉 `n` 个前 `n` 大的数呢?这个是可行的,因为每次 `pop` 出去,元素都只会减一,这个是非常有规律的。 +- 为了接下来的描述更加清晰易懂,还需要再定义 1 个值, `thresholdValue` 为操作 `n` 次以后,当前 `inventory` 数组的最大值。关于 `thresholdValue` 的理解,这里要说明一下。 `thresholdValue` 的来源有 2 种,一种是本来数组里面就有这个值,还有一种来源是 `inventory[i]` 元素减少到了 `thresholdValue` 这个值。举个例子:原始数组是 [2,3,3,4,5],`orders` = 4,取 4 次以后,剩下的数组是 [2,2,3,3,3]。3 个 3 里面其中一个 3 就来自于 `4-1=3`,或者 `5-2=3`。 +- 用二分搜索在 [0,max(`inventory`)] 区间内找到这个 `thresholdValue` 值,能满足下列不等式的最小 `thresholdValue` 值: + + $$\sum_{inventory[i]\geqslant thresholdValue}^{} \left ( inventory[i] - thresholdValue \right )\leqslant orders$$ + + `thresholdValue` 越小,不等式左边的值越大,随着 `thresholdValue` 的增大,不等式左边的值越来越小,直到刚刚能小于等于 `orders`。求出了 `thresholdValue` 值以后,还需要再判断有多少值等于 `thresholdValue - 1` 值了。 + + ![https://img.halfrost.com/Leetcode/leetcode_1648.png](https://img.halfrost.com/Leetcode/leetcode_1648.png) + +- 还是举上面的例子,原始数组是 [2,3,3,4,5],`orders` = 4,我们可以求得 `thresholdValue` = 3 。`inventory[i]` > `thresholdValue` 的那部分 100% 的要取走,`thresholdValue` 就像一个水平面,突出水平面的那些都要拿走,每列的值按照等差数列求和公式计算即可。但是 `orders` - `thresholdValue` = 1,说明水平面以下还要拿走一个,即 `thresholdValue` 线下的虚线框里面的那 4 个球,还需要任意取走一个。最后总的结果是这 2 部分的总和,( ( 5 + 4 ) + 4 ) + 3 = 16 。 + +## 代码 + +```go +package leetcode + +import ( + "container/heap" +) + +// 解法一 贪心 + 二分搜索 +func maxProfit(inventory []int, orders int) int { + maxItem, thresholdValue, count, res, mod := 0, -1, 0, 0, 1000000007 + for i := 0; i < len(inventory); i++ { + if inventory[i] > maxItem { + maxItem = inventory[i] + } + } + low, high := 0, maxItem + for low <= high { + mid := low + ((high - low) >> 1) + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-mid, 0) + } + if count <= orders { + thresholdValue = mid + high = mid - 1 + } else { + low = mid + 1 + } + count = 0 + } + count = 0 + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-thresholdValue, 0) + } + count = orders - count + for i := 0; i < len(inventory); i++ { + if inventory[i] >= thresholdValue { + if count > 0 { + res += (thresholdValue + inventory[i]) * (inventory[i] - thresholdValue + 1) / 2 + count-- + } else { + res += (thresholdValue + 1 + inventory[i]) * (inventory[i] - thresholdValue) / 2 + } + } + } + return res % mod +} +``` \ No newline at end of file diff --git a/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go new file mode 100644 index 00000000..c60b1836 --- /dev/null +++ b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions.go @@ -0,0 +1,106 @@ +package leetcode + +import ( + "github.com/halfrost/LeetCode-Go/template" + "sort" +) + +// 解法一 线段树 SegmentTree +func createSortedArray(instructions []int) int { + if len(instructions) == 0 { + return 0 + } + st, res, mod := template.SegmentCountTree{}, 0, 1000000007 + numsMap, numsArray, tmpArray := discretization1649(instructions) + // 初始化线段树,节点内的值都赋值为 0,即计数为 0 + st.Init(tmpArray, func(i, j int) int { + return 0 + }) + for i := 0; i < len(instructions); i++ { + strictlyLessThan := st.Query(0, numsMap[instructions[i]]-1) + strictlyGreaterThan := st.Query(numsMap[instructions[i]]+1, numsArray[len(numsArray)-1]) + res = (res + min(strictlyLessThan, strictlyGreaterThan)) % mod + st.UpdateCount(numsMap[instructions[i]]) + } + return res +} + +func discretization1649(instructions []int) (map[int]int, []int, []int) { + tmpArray, numsArray, numsMap := []int{}, []int{}, map[int]int{} + for i := 0; i < len(instructions); i++ { + numsMap[instructions[i]] = instructions[i] + } + for _, v := range numsMap { + numsArray = append(numsArray, v) + } + sort.Ints(numsArray) + for i, num := range numsArray { + numsMap[num] = i + } + for i := range numsArray { + tmpArray = append(tmpArray, i) + } + return numsMap, numsArray, tmpArray +} + +func min(a int, b int) int { + if a > b { + return b + } + return a +} + +// 解法二 树状数组 Binary Indexed Tree +func createSortedArray1(instructions []int) int { + b := newBIT(make([]int, 100001)) + var res int + cnt := map[int]int{} + for i, n := range instructions { + less := b.get(n - 1) + greater := i - less - cnt[n] + res = (res + min(less, greater)) % (1e9 + 7) + b.update(n, 1) + cnt[n]++ + } + + return res % (1e9 + 7) +} + +func max(x, y int) int { + if x > y { + return x + } + return y +} + +type BIT struct { + data []int +} + +func newBIT(nums []int) *BIT { + data := make([]int, len(nums)+1) + b := &BIT{data} + for i, n := range nums { + b.update(i, n) + } + + return b +} + +func (b *BIT) update(i, num int) { + i++ + for i < len(b.data) { + b.data[i] += num + i += (i & -i) + } +} + +func (b *BIT) get(i int) int { + i++ + var sum int + for i > 0 { + sum += b.data[i] + i -= (i & -i) + } + return sum +} diff --git a/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions_test.go b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions_test.go new file mode 100644 index 00000000..892fe14f --- /dev/null +++ b/leetcode/1649.Create-Sorted-Array-through-Instructions/1649. Create Sorted Array through Instructions_test.go @@ -0,0 +1,52 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question1649 struct { + para1649 + ans1649 +} + +// para 是参数 +// one 代表第一个参数 +type para1649 struct { + instructions []int +} + +// ans 是答案 +// one 代表第一个答案 +type ans1649 struct { + one int +} + +func Test_Problem1649(t *testing.T) { + + qs := []question1649{ + + { + para1649{[]int{1, 5, 6, 2}}, + ans1649{1}, + }, + + { + para1649{[]int{1, 2, 3, 6, 5, 4}}, + ans1649{3}, + }, + + { + para1649{[]int{1, 3, 3, 3, 2, 4, 2, 1, 2}}, + ans1649{4}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 1649------------------------\n") + + for _, q := range qs { + _, p := q.ans1649, q.para1649 + fmt.Printf("【input】:%v 【output】:%v \n", p, createSortedArray(p.instructions)) + } + fmt.Printf("\n\n\n") +} diff --git a/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md b/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md new file mode 100644 index 00000000..2f99c307 --- /dev/null +++ b/leetcode/1649.Create-Sorted-Array-through-Instructions/README.md @@ -0,0 +1,189 @@ +# [1649. Create Sorted Array through Instructions](https://leetcode.com/problems/create-sorted-array-through-instructions/) + +## 题目 + +Given an integer array `instructions`, you are asked to create a sorted array from the elements in `instructions`. You start with an empty container `nums`. For each element from **left to right** in `instructions`, insert it into `nums`. The **cost** of each insertion is the **minimum** of the following: + +- The number of elements currently in `nums` that are **strictly less than** `instructions[i]`. +- The number of elements currently in `nums` that are **strictly greater than** `instructions[i]`. + +For example, if inserting element `3` into `nums = [1,2,3,5]`, the **cost** of insertion is `min(2, 1)` (elements `1` and `2` are less than `3`, element `5` is greater than `3`) and `nums` will become `[1,2,3,3,5]`. + +Return *the **total cost** to insert all elements from* `instructions` *into* `nums`. Since the answer may be large, return it **modulo** `10^9 + 7` + +**Example 1:** + +``` +Input: instructions = [1,5,6,2] +Output: 1 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 5 with cost min(1, 0) = 0, now nums = [1,5]. +Insert 6 with cost min(2, 0) = 0, now nums = [1,5,6]. +Insert 2 with cost min(1, 2) = 1, now nums = [1,2,5,6]. +The total cost is 0 + 0 + 0 + 1 = 1. +``` + +**Example 2:** + +``` +Input: instructions = [1,2,3,6,5,4] +Output: 3 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 2 with cost min(1, 0) = 0, now nums = [1,2]. +Insert 3 with cost min(2, 0) = 0, now nums = [1,2,3]. +Insert 6 with cost min(3, 0) = 0, now nums = [1,2,3,6]. +Insert 5 with cost min(3, 1) = 1, now nums = [1,2,3,5,6]. +Insert 4 with cost min(3, 2) = 2, now nums = [1,2,3,4,5,6]. +The total cost is 0 + 0 + 0 + 0 + 1 + 2 = 3. +``` + +**Example 3:** + +``` +Input: instructions = [1,3,3,3,2,4,2,1,2] +Output: 4 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3,3]. +Insert 2 with cost min(1, 3) = 1, now nums = [1,2,3,3,3]. +Insert 4 with cost min(5, 0) = 0, now nums = [1,2,3,3,3,4]. +Insert 2 with cost min(1, 4) = 1, now nums = [1,2,2,3,3,3,4]. +Insert 1 with cost min(0, 6) = 0, now nums = [1,1,2,2,3,3,3,4]. +Insert 2 with cost min(2, 4) = 2, now nums = [1,1,2,2,2,3,3,3,4]. +The total cost is 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4. +``` + +**Constraints:** + +- `1 <= instructions.length <= 105` +- `1 <= instructions[i] <= 105` + +## 题目大意 + +给你一个整数数组 instructions ,你需要根据 instructions 中的元素创建一个有序数组。一开始你有一个空的数组 nums ,你需要 从左到右 遍历 instructions 中的元素,将它们依次插入 nums 数组中。每一次插入操作的 代价 是以下两者的 较小值 : + +- nums 中 严格小于 instructions[i] 的数字数目。 +- nums 中 严格大于 instructions[i] 的数字数目。 + +比方说,如果要将 3 插入到 nums = [1,2,3,5] ,那么插入操作的 代价 为 min(2, 1) (元素 1 和 2 小于 3 ,元素 5 大于 3 ),插入后 nums 变成 [1,2,3,3,5] 。请你返回将 instructions 中所有元素依次插入 nums 后的 总最小代价 。由于答案会很大,请将它对 10^9 + 7 取余 后返回。 + +## 解题思路 + +- 给出一个数组,要求将其中的元素从头开始往另外一个空数组中插入,每次插入前,累加代价值 cost = min(**strictly less than**, **strictly greater than**)。最后输出累加值。 +- 这一题虽然是 Hard 题,但是读完题以后就可以判定这是模板题了。可以用线段树和树状数组来解决。这里简单说说线段树的思路吧,先将待插入的数组排序,获得总的区间。每次循环做 4 步:2 次 `query` 分别得到 `strictlyLessThan` 和 `strictlyGreaterThan` ,再比较出两者中的最小值累加,最后一步就是 `update`。 +- 由于题目给的数据比较大,所以建立线段树之前记得要先离散化。这一题核心代码不超过 10 行,其他的都是模板代码。具体实现见代码。 + +## 代码 + +```go +package leetcode + +import ( + "github.com/halfrost/LeetCode-Go/template" + "sort" +) + +// 解法一 线段树 SegmentTree +func createSortedArray(instructions []int) int { + if len(instructions) == 0 { + return 0 + } + st, res, mod := template.SegmentCountTree{}, 0, 1000000007 + numsMap, numsArray, tmpArray := discretization1649(instructions) + // 初始化线段树,节点内的值都赋值为 0,即计数为 0 + st.Init(tmpArray, func(i, j int) int { + return 0 + }) + for i := 0; i < len(instructions); i++ { + strictlyLessThan := st.Query(0, numsMap[instructions[i]]-1) + strictlyGreaterThan := st.Query(numsMap[instructions[i]]+1, numsArray[len(numsArray)-1]) + res = (res + min(strictlyLessThan, strictlyGreaterThan)) % mod + st.UpdateCount(numsMap[instructions[i]]) + } + return res +} + +func discretization1649(instructions []int) (map[int]int, []int, []int) { + tmpArray, numsArray, numsMap := []int{}, []int{}, map[int]int{} + for i := 0; i < len(instructions); i++ { + numsMap[instructions[i]] = instructions[i] + } + for _, v := range numsMap { + numsArray = append(numsArray, v) + } + sort.Ints(numsArray) + for i, num := range numsArray { + numsMap[num] = i + } + for i := range numsArray { + tmpArray = append(tmpArray, i) + } + return numsMap, numsArray, tmpArray +} + +func min(a int, b int) int { + if a > b { + return b + } + return a +} + +// 解法二 树状数组 Binary Indexed Tree +func createSortedArray1(instructions []int) int { + b := newBIT(make([]int, 100001)) + var res int + cnt := map[int]int{} + for i, n := range instructions { + less := b.get(n - 1) + greater := i - less - cnt[n] + res = (res + min(less, greater)) % (1e9 + 7) + b.update(n, 1) + cnt[n]++ + } + + return res % (1e9 + 7) +} + +func max(x, y int) int { + if x > y { + return x + } + return y +} + +type BIT struct { + data []int +} + +func newBIT(nums []int) *BIT { + data := make([]int, len(nums)+1) + b := &BIT{data} + for i, n := range nums { + b.update(i, n) + } + + return b +} + +func (b *BIT) update(i, num int) { + i++ + for i < len(b.data) { + b.data[i] += num + i += (i & -i) + } +} + +func (b *BIT) get(i int) int { + i++ + var sum int + for i > 0 { + sum += b.data[i] + i -= (i & -i) + } + return sum +} +``` \ No newline at end of file diff --git a/leetcode/5561.Get-Maximum-in-Generated-Array/5561. Get Maximum in Generated Array_test.go b/leetcode/5561.Get-Maximum-in-Generated-Array/5561. Get Maximum in Generated Array_test.go deleted file mode 100644 index 8af6a6fc..00000000 --- a/leetcode/5561.Get-Maximum-in-Generated-Array/5561. Get Maximum in Generated Array_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package leetcode - -import ( - "fmt" - "testing" -) - -type question5561 struct { - para5561 - ans5561 -} - -// para 是参数 -// one 代表第一个参数 -type para5561 struct { - n int -} - -// ans 是答案 -// one 代表第一个答案 -type ans5561 struct { - one int -} - -func Test_Problem5561(t *testing.T) { - - qs := []question5561{ - - { - para5561{7}, - ans5561{3}, - }, - - { - para5561{2}, - ans5561{1}, - }, - - { - para5561{3}, - ans5561{2}, - }, - - { - para5561{0}, - ans5561{0}, - }, - - { - para5561{1}, - ans5561{1}, - }, - } - - fmt.Printf("------------------------Leetcode Problem 5561------------------------\n") - - for _, q := range qs { - _, p := q.ans5561, q.para5561 - fmt.Printf("【input】:%v 【output】:%v \n", p, getMaximumGenerated(p.n)) - } - fmt.Printf("\n\n\n") -} diff --git a/leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique_test.go b/leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique_test.go deleted file mode 100644 index 1a3b33d3..00000000 --- a/leetcode/5562.Minimum-Deletions-to-Make-Character-Frequencies-Unique/5562. Minimum Deletions to Make Character Frequencies Unique_test.go +++ /dev/null @@ -1,62 +0,0 @@ -package leetcode - -import ( - "fmt" - "testing" -) - -type question5562 struct { - para5562 - ans5562 -} - -// para 是参数 -// one 代表第一个参数 -type para5562 struct { - s string -} - -// ans 是答案 -// one 代表第一个答案 -type ans5562 struct { - one int -} - -func Test_Problem5562(t *testing.T) { - - qs := []question5562{ - - { - para5562{"aab"}, - ans5562{0}, - }, - - { - para5562{"aaabbbcc"}, - ans5562{2}, - }, - - { - para5562{"ceabaacb"}, - ans5562{2}, - }, - - { - para5562{""}, - ans5562{0}, - }, - - { - para5562{"abcabc"}, - ans5562{3}, - }, - } - - fmt.Printf("------------------------Leetcode Problem 5562------------------------\n") - - for _, q := range qs { - _, p := q.ans5562, q.para5562 - fmt.Printf("【input】:%v 【output】:%v \n", p, minDeletions(p.s)) - } - fmt.Printf("\n\n\n") -} diff --git a/leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls_test.go b/leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls_test.go deleted file mode 100644 index 9d48c4b3..00000000 --- a/leetcode/5563.Sell-Diminishing-Valued-Colored-Balls/5563. Sell Diminishing-Valued Colored Balls_test.go +++ /dev/null @@ -1,58 +0,0 @@ -package leetcode - -import ( - "fmt" - "testing" -) - -type question5563 struct { - para5563 - ans5563 -} - -// para 是参数 -// one 代表第一个参数 -type para5563 struct { - inventory []int - orders int -} - -// ans 是答案 -// one 代表第一个答案 -type ans5563 struct { - one int -} - -func Test_Problem5563(t *testing.T) { - - qs := []question5563{ - - { - para5563{[]int{2, 5}, 4}, - ans5563{14}, - }, - - { - para5563{[]int{3, 5}, 6}, - ans5563{19}, - }, - - { - para5563{[]int{2, 8, 4, 10, 6}, 20}, - ans5563{110}, - }, - - { - para5563{[]int{1000000000}, 1000000000}, - ans5563{21}, - }, - } - - fmt.Printf("------------------------Leetcode Problem 5563------------------------\n") - - for _, q := range qs { - _, p := q.ans5563, q.para5563 - fmt.Printf("【input】:%v 【output】:%v \n", p, maxProfit(p.inventory, p.orders)) - } - fmt.Printf("\n\n\n") -} diff --git a/website/content/ChapterFour/1646.Get-Maximum-in-Generated-Array.md b/website/content/ChapterFour/1646.Get-Maximum-in-Generated-Array.md new file mode 100644 index 00000000..a703bba7 --- /dev/null +++ b/website/content/ChapterFour/1646.Get-Maximum-in-Generated-Array.md @@ -0,0 +1,96 @@ +# [1646. Get Maximum in Generated Array](https://leetcode.com/problems/get-maximum-in-generated-array/) + + +## 题目 + +You are given an integer `n`. An array `nums` of length `n + 1` is generated in the following way: + +- `nums[0] = 0` +- `nums[1] = 1` +- `nums[2 * i] = nums[i]` when `2 <= 2 * i <= n` +- `nums[2 * i + 1] = nums[i] + nums[i + 1]` when `2 <= 2 * i + 1 <= n` + +Return *****the **maximum** integer in the array* `nums`. + +**Example 1:** + +``` +Input: n = 7 +Output: 3 +Explanation: According to the given rules: + nums[0] = 0 + nums[1] = 1 + nums[(1 * 2) = 2] = nums[1] = 1 + nums[(1 * 2) + 1 = 3] = nums[1] + nums[2] = 1 + 1 = 2 + nums[(2 * 2) = 4] = nums[2] = 1 + nums[(2 * 2) + 1 = 5] = nums[2] + nums[3] = 1 + 2 = 3 + nums[(3 * 2) = 6] = nums[3] = 2 + nums[(3 * 2) + 1 = 7] = nums[3] + nums[4] = 2 + 1 = 3 +Hence, nums = [0,1,1,2,1,3,2,3], and the maximum is 3. + +``` + +**Example 2:** + +``` +Input: n = 2 +Output: 1 +Explanation: According to the given rules, the maximum between nums[0], nums[1], and nums[2] is 1. + +``` + +**Example 3:** + +``` +Input: n = 3 +Output: 2 +Explanation: According to the given rules, the maximum between nums[0], nums[1], nums[2], and nums[3] is 2. + +``` + +**Constraints:** + +- `0 <= n <= 100` + +## 题目大意 + +给你一个整数 n 。按下述规则生成一个长度为 n + 1 的数组 nums : + +- nums[0] = 0 +- nums[1] = 1 +- 当 2 <= 2 * i <= n 时,nums[2 * i] = nums[i] +- 当 2 <= 2 * i + 1 <= n 时,nums[2 * i + 1] = nums[i] + nums[i + 1] + +返回生成数组 nums 中的 最大值。 + +## 解题思路 + +- 给出一个 n + 1 的数组,并按照生成规则生成这个数组,求出这个数组中的最大值。 +- 简单题,按照题意生成数组,边生成边记录和更新最大值即可。 +- 注意边界条件,当 n 为 0 的时候,数组里面只有一个元素 0 。 + +## 代码 + +```go +package leetcode + +func getMaximumGenerated(n int) int { + if n == 0 { + return 0 + } + nums, max := make([]int, n+1), 0 + nums[0], nums[1] = 0, 1 + for i := 0; i <= n; i++ { + if nums[i] > max { + max = nums[i] + } + if 2*i >= 2 && 2*i <= n { + nums[2*i] = nums[i] + } + if 2*i+1 >= 2 && 2*i+1 <= n { + nums[2*i+1] = nums[i] + nums[i+1] + } + } + return max +} +``` \ No newline at end of file diff --git a/website/content/ChapterFour/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique.md b/website/content/ChapterFour/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique.md new file mode 100644 index 00000000..e6b2fff8 --- /dev/null +++ b/website/content/ChapterFour/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique.md @@ -0,0 +1,89 @@ +# [1647. Minimum Deletions to Make Character Frequencies Unique](https://leetcode.com/problems/minimum-deletions-to-make-character-frequencies-unique/) + + +## 题目 + +A string `s` is called **good** if there are no two different characters in `s` that have the same **frequency**. + +Given a string `s`, return *the **minimum** number of characters you need to delete to make* `s` ***good**.* + +The **frequency** of a character in a string is the number of times it appears in the string. For example, in the string `"aab"`, the **frequency** of `'a'` is `2`, while the **frequency** of `'b'` is `1`. + +**Example 1:** + +``` +Input: s = "aab" +Output: 0 +Explanation: s is already good. + +``` + +**Example 2:** + +``` +Input: s = "aaabbbcc" +Output: 2 +Explanation: You can delete two 'b's resulting in the good string "aaabcc". +Another way it to delete one 'b' and one 'c' resulting in the good string "aaabbc". +``` + +**Example 3:** + +``` +Input: s = "ceabaacb" +Output: 2 +Explanation: You can delete both 'c's resulting in the good string "eabaab". +Note that we only care about characters that are still in the string at the end (i.e. frequency of 0 is ignored). + +``` + +**Constraints:** + +- `1 <= s.length <= 105` +- `s` contains only lowercase English letters. + +## 题目大意 + +如果字符串 s 中 不存在 两个不同字符 频次 相同的情况,就称 s 是 优质字符串 。 + +给你一个字符串 s,返回使 s 成为优质字符串需要删除的最小字符数。 + +字符串中字符的 频次 是该字符在字符串中的出现次数。例如,在字符串 "aab" 中,'a' 的频次是 2,而 'b' 的频次是 1 。 + +**提示:** + +- `1 <= s.length <= 105` +- `s` 仅含小写英文字母 + +## 解题思路 + +- 给出一个字符串 s,要求输出使 s 变成“优质字符串”需要删除的最小字符数。“优质字符串”的定义是:字符串 s 中不存在频次相同的两个不同字符。 +- 首先将 26 个字母在字符串中的频次分别统计出来,然后把频次从大到小排列,从频次大的开始,依次调整:例如,假设前一个和后一个频次相等,就把前一个字符删除一个,频次减一,再次排序,如果频次还相等,继续调整,如果频次不同了,游标往后移,继续调整后面的频次。直到所有的频次都不同了,就可以输出最终结果了。 +- 这里需要注意频次为 0 的情况,即字母都被删光了。频次为 0 以后,就不需要再比较了。 + +## 代码 + +```go +package leetcode + +import ( + "sort" +) + +func minDeletions(s string) int { + frequency, res := make([]int, 26), 0 + for i := 0; i < len(s); i++ { + frequency[s[i]-'a']++ + } + sort.Sort(sort.Reverse(sort.IntSlice(frequency))) + for i := 1; i <= 25; i++ { + if frequency[i] == frequency[i-1] && frequency[i] != 0 { + res++ + frequency[i]-- + sort.Sort(sort.Reverse(sort.IntSlice(frequency))) + i-- + } + } + return res +} +``` \ No newline at end of file diff --git a/website/content/ChapterFour/1648.Sell-Diminishing-Valued-Colored-Balls.md b/website/content/ChapterFour/1648.Sell-Diminishing-Valued-Colored-Balls.md new file mode 100644 index 00000000..bddd91b3 --- /dev/null +++ b/website/content/ChapterFour/1648.Sell-Diminishing-Valued-Colored-Balls.md @@ -0,0 +1,131 @@ +# [1648. Sell Diminishing-Valued Colored Balls](https://leetcode.com/problems/sell-diminishing-valued-colored-balls/) + + +## 题目 + +You have an `inventory` of different colored balls, and there is a customer that wants `orders` balls of **any** color. + +The customer weirdly values the colored balls. Each colored ball's value is the number of balls **of that color** you currently have in your `inventory`. For example, if you own `6` yellow balls, the customer would pay `6` for the first yellow ball. After the transaction, there are only `5` yellow balls left, so the next yellow ball is then valued at `5` (i.e., the value of the balls decreases as you sell more to the customer). + +You are given an integer array, `inventory`, where `inventory[i]` represents the number of balls of the `ith` color that you initially own. You are also given an integer `orders`, which represents the total number of balls that the customer wants. You can sell the balls **in any order**. + +Return *the **maximum** total value that you can attain after selling* `orders` *colored balls*. As the answer may be too large, return it **modulo** `109 + 7`. + +**Example 1:** + +![https://assets.leetcode.com/uploads/2020/11/05/jj.gif](https://assets.leetcode.com/uploads/2020/11/05/jj.gif) + +``` +Input: inventory = [2,5], orders = 4 +Output: 14 +Explanation: Sell the 1st color 1 time (2) and the 2nd color 3 times (5 + 4 + 3). +The maximum total value is 2 + 5 + 4 + 3 = 14. + +``` + +**Example 2:** + +``` +Input: inventory = [3,5], orders = 6 +Output: 19 +Explanation: Sell the 1st color 2 times (3 + 2) and the 2nd color 4 times (5 + 4 + 3 + 2). +The maximum total value is 3 + 2 + 5 + 4 + 3 + 2 = 19. +``` + +**Example 3:** + +``` +Input: inventory = [2,8,4,10,6], orders = 20 +Output: 110 +``` + +**Example 4:** + +``` +Input: inventory = [1000000000], orders = 1000000000 +Output: 21 +Explanation: Sell the 1st color 1000000000 times for a total value of 500000000500000000. 500000000500000000 modulo 109 + 7 = 21. +``` + +**Constraints:** + +- `1 <= inventory.length <= 10^5` +- `1 <= inventory[i] <= 10^9` +- `1 <= orders <= min(sum(inventory[i]), 10^9)` + +## 题目大意 + +你有一些球的库存 inventory ,里面包含着不同颜色的球。一个顾客想要 任意颜色 总数为 orders 的球。这位顾客有一种特殊的方式衡量球的价值:每个球的价值是目前剩下的 同色球 的数目。比方说还剩下 6 个黄球,那么顾客买第一个黄球的时候该黄球的价值为 6 。这笔交易以后,只剩下 5 个黄球了,所以下一个黄球的价值为 5 (也就是球的价值随着顾客购买同色球是递减的) + +给你整数数组 inventory ,其中 inventory[i] 表示第 i 种颜色球一开始的数目。同时给你整数 orders ,表示顾客总共想买的球数目。你可以按照 任意顺序 卖球。请你返回卖了 orders 个球以后 最大 总价值之和。由于答案可能会很大,请你返回答案对 109 + 7 取余数 的结果。 + +提示: + +- 1 <= inventory.length <= 10^5 +- 1 <= inventory[i] <= 10^9 +- 1 <= orders <= min(sum(inventory[i]), 10^9) + +## 解题思路 + +- 给出一个 `inventory` 数组和 `orders` 次操作,要求输出数组中前 `orders` 大个元素累加和。需要注意的是,每累加一个元素 `inventory[i]`,这个元素都会减一,下次再累加的时候,需要选取更新以后的数组的最大值。 +- 拿到这个题目以后很容易想到优先队列,建立大根堆以后,`pop` 出当前最大值 `maxItem`,累加,以后把 `maxItem` 减一再 `push` 回去。循环执行 `orders` 次以后即是最终结果。题目是这个意思,但是我们不能这么写代码,因为题目条件里面给出了 `orders` 的数据大小。orders 最大为 10^9。按照优先队列的这个方法一定会超时,时间复杂度为 O(orders⋅logn)。那就换一个思路。优先队列这个思路中,重复操作了 `orders` 次,其实在这些操作中,有一些是没有必要的废操作。这些大量的“废”操作导致了超时。试想,在 `orders` 次操作中,能否合并 `n` 个 `pop` 操作,一口气先 `pop` 掉 `n` 个前 `n` 大的数呢?这个是可行的,因为每次 `pop` 出去,元素都只会减一,这个是非常有规律的。 +- 为了接下来的描述更加清晰易懂,还需要再定义 1 个值, `thresholdValue` 为操作 `n` 次以后,当前 `inventory` 数组的最大值。关于 `thresholdValue` 的理解,这里要说明一下。 `thresholdValue` 的来源有 2 种,一种是本来数组里面就有这个值,还有一种来源是 `inventory[i]` 元素减少到了 `thresholdValue` 这个值。举个例子:原始数组是 [2,3,3,4,5],`orders` = 4,取 4 次以后,剩下的数组是 [2,2,3,3,3]。3 个 3 里面其中一个 3 就来自于 `4-1=3`,或者 `5-2=3`。 +- 用二分搜索在 [0,max(`inventory`)] 区间内找到这个 `thresholdValue` 值,能满足下列不等式的最小 `thresholdValue` 值: + + $$\sum_{inventory[i]\geqslant thresholdValue}^{} \left ( inventory[i] - thresholdValue \right )\leqslant orders$$ + + `thresholdValue` 越小,不等式左边的值越大,随着 `thresholdValue` 的增大,不等式左边的值越来越小,直到刚刚能小于等于 `orders`。求出了 `thresholdValue` 值以后,还需要再判断有多少值等于 `thresholdValue - 1` 值了。 + + ![https://img.halfrost.com/Leetcode/leetcode_1648.png](https://img.halfrost.com/Leetcode/leetcode_1648.png) + +- 还是举上面的例子,原始数组是 [2,3,3,4,5],`orders` = 4,我们可以求得 `thresholdValue` = 3 。`inventory[i]` > `thresholdValue` 的那部分 100% 的要取走,`thresholdValue` 就像一个水平面,突出水平面的那些都要拿走,每列的值按照等差数列求和公式计算即可。但是 `orders` - `thresholdValue` = 1,说明水平面以下还要拿走一个,即 `thresholdValue` 线下的虚线框里面的那 4 个球,还需要任意取走一个。最后总的结果是这 2 部分的总和,( ( 5 + 4 ) + 4 ) + 3 = 16 。 + +## 代码 + +```go +package leetcode + +import ( + "container/heap" +) + +// 解法一 贪心 + 二分搜索 +func maxProfit(inventory []int, orders int) int { + maxItem, thresholdValue, count, res, mod := 0, -1, 0, 0, 1000000007 + for i := 0; i < len(inventory); i++ { + if inventory[i] > maxItem { + maxItem = inventory[i] + } + } + low, high := 0, maxItem + for low <= high { + mid := low + ((high - low) >> 1) + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-mid, 0) + } + if count <= orders { + thresholdValue = mid + high = mid - 1 + } else { + low = mid + 1 + } + count = 0 + } + count = 0 + for i := 0; i < len(inventory); i++ { + count += max(inventory[i]-thresholdValue, 0) + } + count = orders - count + for i := 0; i < len(inventory); i++ { + if inventory[i] >= thresholdValue { + if count > 0 { + res += (thresholdValue + inventory[i]) * (inventory[i] - thresholdValue + 1) / 2 + count-- + } else { + res += (thresholdValue + 1 + inventory[i]) * (inventory[i] - thresholdValue) / 2 + } + } + } + return res % mod +} +``` \ No newline at end of file diff --git a/website/content/ChapterFour/1649.Create-Sorted-Array-through-Instructions.md b/website/content/ChapterFour/1649.Create-Sorted-Array-through-Instructions.md new file mode 100644 index 00000000..2f99c307 --- /dev/null +++ b/website/content/ChapterFour/1649.Create-Sorted-Array-through-Instructions.md @@ -0,0 +1,189 @@ +# [1649. Create Sorted Array through Instructions](https://leetcode.com/problems/create-sorted-array-through-instructions/) + +## 题目 + +Given an integer array `instructions`, you are asked to create a sorted array from the elements in `instructions`. You start with an empty container `nums`. For each element from **left to right** in `instructions`, insert it into `nums`. The **cost** of each insertion is the **minimum** of the following: + +- The number of elements currently in `nums` that are **strictly less than** `instructions[i]`. +- The number of elements currently in `nums` that are **strictly greater than** `instructions[i]`. + +For example, if inserting element `3` into `nums = [1,2,3,5]`, the **cost** of insertion is `min(2, 1)` (elements `1` and `2` are less than `3`, element `5` is greater than `3`) and `nums` will become `[1,2,3,3,5]`. + +Return *the **total cost** to insert all elements from* `instructions` *into* `nums`. Since the answer may be large, return it **modulo** `10^9 + 7` + +**Example 1:** + +``` +Input: instructions = [1,5,6,2] +Output: 1 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 5 with cost min(1, 0) = 0, now nums = [1,5]. +Insert 6 with cost min(2, 0) = 0, now nums = [1,5,6]. +Insert 2 with cost min(1, 2) = 1, now nums = [1,2,5,6]. +The total cost is 0 + 0 + 0 + 1 = 1. +``` + +**Example 2:** + +``` +Input: instructions = [1,2,3,6,5,4] +Output: 3 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 2 with cost min(1, 0) = 0, now nums = [1,2]. +Insert 3 with cost min(2, 0) = 0, now nums = [1,2,3]. +Insert 6 with cost min(3, 0) = 0, now nums = [1,2,3,6]. +Insert 5 with cost min(3, 1) = 1, now nums = [1,2,3,5,6]. +Insert 4 with cost min(3, 2) = 2, now nums = [1,2,3,4,5,6]. +The total cost is 0 + 0 + 0 + 0 + 1 + 2 = 3. +``` + +**Example 3:** + +``` +Input: instructions = [1,3,3,3,2,4,2,1,2] +Output: 4 +Explanation: Begin with nums = []. +Insert 1 with cost min(0, 0) = 0, now nums = [1]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3]. +Insert 3 with cost min(1, 0) = 0, now nums = [1,3,3,3]. +Insert 2 with cost min(1, 3) = 1, now nums = [1,2,3,3,3]. +Insert 4 with cost min(5, 0) = 0, now nums = [1,2,3,3,3,4]. +Insert 2 with cost min(1, 4) = 1, now nums = [1,2,2,3,3,3,4]. +Insert 1 with cost min(0, 6) = 0, now nums = [1,1,2,2,3,3,3,4]. +Insert 2 with cost min(2, 4) = 2, now nums = [1,1,2,2,2,3,3,3,4]. +The total cost is 0 + 0 + 0 + 0 + 1 + 0 + 1 + 0 + 2 = 4. +``` + +**Constraints:** + +- `1 <= instructions.length <= 105` +- `1 <= instructions[i] <= 105` + +## 题目大意 + +给你一个整数数组 instructions ,你需要根据 instructions 中的元素创建一个有序数组。一开始你有一个空的数组 nums ,你需要 从左到右 遍历 instructions 中的元素,将它们依次插入 nums 数组中。每一次插入操作的 代价 是以下两者的 较小值 : + +- nums 中 严格小于 instructions[i] 的数字数目。 +- nums 中 严格大于 instructions[i] 的数字数目。 + +比方说,如果要将 3 插入到 nums = [1,2,3,5] ,那么插入操作的 代价 为 min(2, 1) (元素 1 和 2 小于 3 ,元素 5 大于 3 ),插入后 nums 变成 [1,2,3,3,5] 。请你返回将 instructions 中所有元素依次插入 nums 后的 总最小代价 。由于答案会很大,请将它对 10^9 + 7 取余 后返回。 + +## 解题思路 + +- 给出一个数组,要求将其中的元素从头开始往另外一个空数组中插入,每次插入前,累加代价值 cost = min(**strictly less than**, **strictly greater than**)。最后输出累加值。 +- 这一题虽然是 Hard 题,但是读完题以后就可以判定这是模板题了。可以用线段树和树状数组来解决。这里简单说说线段树的思路吧,先将待插入的数组排序,获得总的区间。每次循环做 4 步:2 次 `query` 分别得到 `strictlyLessThan` 和 `strictlyGreaterThan` ,再比较出两者中的最小值累加,最后一步就是 `update`。 +- 由于题目给的数据比较大,所以建立线段树之前记得要先离散化。这一题核心代码不超过 10 行,其他的都是模板代码。具体实现见代码。 + +## 代码 + +```go +package leetcode + +import ( + "github.com/halfrost/LeetCode-Go/template" + "sort" +) + +// 解法一 线段树 SegmentTree +func createSortedArray(instructions []int) int { + if len(instructions) == 0 { + return 0 + } + st, res, mod := template.SegmentCountTree{}, 0, 1000000007 + numsMap, numsArray, tmpArray := discretization1649(instructions) + // 初始化线段树,节点内的值都赋值为 0,即计数为 0 + st.Init(tmpArray, func(i, j int) int { + return 0 + }) + for i := 0; i < len(instructions); i++ { + strictlyLessThan := st.Query(0, numsMap[instructions[i]]-1) + strictlyGreaterThan := st.Query(numsMap[instructions[i]]+1, numsArray[len(numsArray)-1]) + res = (res + min(strictlyLessThan, strictlyGreaterThan)) % mod + st.UpdateCount(numsMap[instructions[i]]) + } + return res +} + +func discretization1649(instructions []int) (map[int]int, []int, []int) { + tmpArray, numsArray, numsMap := []int{}, []int{}, map[int]int{} + for i := 0; i < len(instructions); i++ { + numsMap[instructions[i]] = instructions[i] + } + for _, v := range numsMap { + numsArray = append(numsArray, v) + } + sort.Ints(numsArray) + for i, num := range numsArray { + numsMap[num] = i + } + for i := range numsArray { + tmpArray = append(tmpArray, i) + } + return numsMap, numsArray, tmpArray +} + +func min(a int, b int) int { + if a > b { + return b + } + return a +} + +// 解法二 树状数组 Binary Indexed Tree +func createSortedArray1(instructions []int) int { + b := newBIT(make([]int, 100001)) + var res int + cnt := map[int]int{} + for i, n := range instructions { + less := b.get(n - 1) + greater := i - less - cnt[n] + res = (res + min(less, greater)) % (1e9 + 7) + b.update(n, 1) + cnt[n]++ + } + + return res % (1e9 + 7) +} + +func max(x, y int) int { + if x > y { + return x + } + return y +} + +type BIT struct { + data []int +} + +func newBIT(nums []int) *BIT { + data := make([]int, len(nums)+1) + b := &BIT{data} + for i, n := range nums { + b.update(i, n) + } + + return b +} + +func (b *BIT) update(i, num int) { + i++ + for i < len(b.data) { + b.data[i] += num + i += (i & -i) + } +} + +func (b *BIT) get(i int) int { + i++ + var sum int + for i > 0 { + sum += b.data[i] + i -= (i & -i) + } + return sum +} +``` \ No newline at end of file diff --git a/website/content/menu/index.md b/website/content/menu/index.md index abd00fce..119f9b1c 100644 --- a/website/content/menu/index.md +++ b/website/content/menu/index.md @@ -548,4 +548,8 @@ headless: true - [1470.Shuffle-the-Array]({{< relref "/ChapterFour/1470.Shuffle-the-Array.md" >}}) - [1480.Running-Sum-of-1d-Array]({{< relref "/ChapterFour/1480.Running-Sum-of-1d-Array.md" >}}) - [1512.Number-of-Good-Pairs]({{< relref "/ChapterFour/1512.Number-of-Good-Pairs.md" >}}) + - [1646.Get-Maximum-in-Generated-Array]({{< relref "/ChapterFour/1646.Get-Maximum-in-Generated-Array.md" >}}) + - [1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique]({{< relref "/ChapterFour/1647.Minimum-Deletions-to-Make-Character-Frequencies-Unique.md" >}}) + - [1648.Sell-Diminishing-Valued-Colored-Balls]({{< relref "/ChapterFour/1648.Sell-Diminishing-Valued-Colored-Balls.md" >}}) + - [1649.Create-Sorted-Array-through-Instructions]({{< relref "/ChapterFour/1649.Create-Sorted-Array-through-Instructions.md" >}})