diff --git a/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths.go b/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths.go new file mode 100644 index 00000000..c60cedf6 --- /dev/null +++ b/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths.go @@ -0,0 +1,15 @@ +package leetcode + +import ( + "sort" +) + +func sumSubseqWidths(A []int) int { + sort.Ints(A) + res, mod, n, p := 0, 1000000007, len(A), 1 + for i := 0; i < n; i++ { + res = (res + (A[i]-A[n-1-i])*p) % mod + p = (p << 1) % mod + } + return res +} diff --git a/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths_test.go b/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths_test.go new file mode 100644 index 00000000..6a0481dc --- /dev/null +++ b/Algorithms/0891. Sum of Subsequence Widths/891. Sum of Subsequence Widths_test.go @@ -0,0 +1,47 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question891 struct { + para891 + ans891 +} + +// para 是参数 +// one 代表第一个参数 +type para891 struct { + one []int +} + +// ans 是答案 +// one 代表第一个答案 +type ans891 struct { + one int +} + +func Test_Problem891(t *testing.T) { + + qs := []question891{ + + question891{ + para891{[]int{2, 1, 3}}, + ans891{6}, + }, + + question891{ + para891{[]int{3, 7, 2, 3}}, + ans891{35}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 891------------------------\n") + + for _, q := range qs { + _, p := q.ans891, q.para891 + fmt.Printf("【input】:%v 【output】:%v\n", p, sumSubseqWidths(p.one)) + } + fmt.Printf("\n\n\n") +} diff --git a/Algorithms/0891. Sum of Subsequence Widths/README.md b/Algorithms/0891. Sum of Subsequence Widths/README.md new file mode 100644 index 00000000..b515e3a3 --- /dev/null +++ b/Algorithms/0891. Sum of Subsequence Widths/README.md @@ -0,0 +1,44 @@ +# [891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths/) + +## 题目 + +Given an array of integers A, consider all non-empty subsequences of A. + +For any sequence S, let the width of S be the difference between the maximum and minimum element of S. + +Return the sum of the widths of all subsequences of A. + +As the answer may be very large, return the answer modulo 10^9 + 7. + + + +Example 1: + +```c +Input: [2,1,3] +Output: 6 +Explanation: +Subsequences are [1], [2], [3], [2,1], [2,3], [1,3], [2,1,3]. +The corresponding widths are 0, 0, 0, 1, 1, 2, 2. +The sum of these widths is 6. +``` + +Note: + +- 1 <= A.length <= 20000 +- 1 <= A[i] <= 20000 + + +## 题目大意 + +给定一个整数数组 A ,考虑 A 的所有非空子序列。对于任意序列 S ,设 S 的宽度是 S 的最大元素和最小元素的差。返回 A 的所有子序列的宽度之和。由于答案可能非常大,请返回答案模 10^9+7。 + + +## 解题思路 + +- 理解题意以后,可以发现,数组内元素的顺序并不影响最终求得的所有子序列的宽度之和。 + + [2,1,3]:[1],[2],[3],[2,1],[2,3],[1,3],[2,1,3] + [1,2,3]:[1],[2],[3],[1,2],[2,3],[1,3],[1,2,3] + 针对每个 A[i] 而言,A[i] 对最终结果的贡献是在子序列的左右两边的时候才有贡献,当 A[i] 位于区间中间的时候,不影响最终结果。先对 A[i] 进行排序,排序以后,有 i 个数 <= A[i],有 n - i - 1 个数 >= A[i]。所以 A[i] 会在 2^i 个子序列的右边界出现,2^(n-i-1) 个左边界出现。那么 A[i] 对最终结果的贡献是 A[i] * 2^i - A[i] * 2^(n-i-1) 。举个例子,[1,4,5,7],A[2] = 5,那么 5 作为右边界的子序列有 2^2 = 4 个,即 [5],[1,5],[4,5],[1,4,5],5 作为左边界的子序列有 2^(4-2-1) = 2 个,即 [5],[5,7]。A[2] = 5 对最终结果的影响是 5 * 2^2 - 5 * 2^(4-2-1) = 10 。 +- 题目要求所有子序列的宽度之和,也就是求每个区间最大值减去最小值的总和。那么 `Ans = SUM{ A[i]*2^i - A[n-i-1] * 2^(n-i-1) }`,其中 `0 <= i < n`。需要注意的是 2^i 可能非常大,所以在计算中就需要去 mod 了,而不是最后计算完了再 mod。注意取模的结合律:`(a * b) % c = (a % c) * (b % c) % c`。 \ No newline at end of file diff --git a/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums.go b/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums.go new file mode 100644 index 00000000..6f7920e3 --- /dev/null +++ b/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums.go @@ -0,0 +1,70 @@ +package leetcode + +// 解法一 最快的解是 DP + 单调栈 +func sumSubarrayMins(A []int) int { + stack, dp, res, mod := []int{}, make([]int, len(A)+1), 0, 1000000007 + stack = append(stack, -1) + + for i := 0; i < len(A); i++ { + for stack[len(stack)-1] != -1 && A[i] <= A[stack[len(stack)-1]] { + stack = stack[:len(stack)-1] + } + dp[i+1] = (dp[stack[len(stack)-1]+1] + (i-stack[len(stack)-1])*A[i]) % mod + stack = append(stack, i) + res += dp[i+1] + res %= mod + } + return res +} + +type pair struct { + val int + count int +} + +// 解法二 用两个单调栈 +func sumSubarrayMins_(A []int) int { + res, n, mod := 0, len(A), 1000000007 + lefts, rights, leftStack, rightStack := make([]int, n), make([]int, n), []*pair{}, []*pair{} + for i := 0; i < n; i++ { + count := 1 + for len(leftStack) != 0 && leftStack[len(leftStack)-1].val > A[i] { + count += leftStack[len(leftStack)-1].count + leftStack = leftStack[:len(leftStack)-1] + } + leftStack = append(leftStack, &pair{val: A[i], count: count}) + lefts[i] = count + } + + for i := n - 1; i >= 0; i-- { + count := 1 + for len(rightStack) != 0 && rightStack[len(rightStack)-1].val >= A[i] { + count += rightStack[len(rightStack)-1].count + rightStack = rightStack[:len(rightStack)-1] + } + rightStack = append(rightStack, &pair{val: A[i], count: count}) + rights[i] = count + } + + for i := 0; i < n; i++ { + res = (res + A[i]*lefts[i]*rights[i]) % mod + } + return res +} + +// 解法三 暴力解法,中间很多重复判断子数组的情况 +func sumSubarrayMins__(A []int) int { + res, mod := 0, 1000000007 + for i := 0; i < len(A); i++ { + stack := []int{} + stack = append(stack, A[i]) + for j := i; j < len(A); j++ { + if stack[len(stack)-1] >= A[j] { + stack = stack[:len(stack)-1] + stack = append(stack, A[j]) + } + res += stack[len(stack)-1] + } + } + return res % mod +} diff --git a/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums_test.go b/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums_test.go new file mode 100644 index 00000000..01b2eb58 --- /dev/null +++ b/Algorithms/0907. Sum of Subarray Minimums/907. Sum of Subarray Minimums_test.go @@ -0,0 +1,42 @@ +package leetcode + +import ( + "fmt" + "testing" +) + +type question907 struct { + para907 + ans907 +} + +// para 是参数 +// one 代表第一个参数 +type para907 struct { + one []int +} + +// ans 是答案 +// one 代表第一个答案 +type ans907 struct { + one int +} + +func Test_Problem907(t *testing.T) { + + qs := []question907{ + + question907{ + para907{[]int{3, 1, 2, 4}}, + ans907{17}, + }, + } + + fmt.Printf("------------------------Leetcode Problem 907------------------------\n") + + for _, q := range qs { + _, p := q.ans907, q.para907 + fmt.Printf("【input】:%v 【output】:%v\n", p, sumSubarrayMins(p.one)) + } + fmt.Printf("\n\n\n") +} diff --git a/Algorithms/0907. Sum of Subarray Minimums/README.md b/Algorithms/0907. Sum of Subarray Minimums/README.md new file mode 100644 index 00000000..d050459f --- /dev/null +++ b/Algorithms/0907. Sum of Subarray Minimums/README.md @@ -0,0 +1,45 @@ +# [907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums/) + +## 题目 + +Given an array of integers A, find the sum of min(B), where B ranges over every (contiguous) subarray of A. + +Since the answer may be large, return the answer modulo 10^9 + 7. + + + +Example 1: + +```c +Input: [3,1,2,4] +Output: 17 +Explanation: Subarrays are [3], [1], [2], [4], [3,1], [1,2], [2,4], [3,1,2], [1,2,4], [3,1,2,4]. +Minimums are 3, 1, 2, 4, 1, 1, 2, 1, 1, 1. Sum is 17. +``` + +Note: + +1. 1 <= A.length <= 30000 +2. 1 <= A[i] <= 30000 + + +## 题目大意 + +给定一个整数数组 A,找到 min(B) 的总和,其中 B 的范围为 A 的每个(连续)子数组。 + +由于答案可能很大,因此返回答案模 10^9 + 7。 + + +## 解题思路 + +- 首先想到的是暴力解法,用两层循环,分别枚举每个连续的子区间,区间内用一个元素记录区间内最小值。每当区间起点发生变化的时候,最终结果都加上上次遍历区间找出的最小值。当整个数组都扫完一遍以后,最终结果模上 10^9+7。 +- 上面暴力解法时间复杂度特别大,因为某个区间的最小值可能是很多区间的最小值,但是我们暴力枚举所有区间,导致要遍历的区间特别多。优化点就在如何减少遍历的区间。第二种思路是用 2 个单调栈。想得到思路是 `res = sum(A[i] * f(i))`,其中 f(i) 是子区间的数,A[i] 是这个子区间内的最小值。为了得到 f(i) 我们需要找到 left[i] 和 right[i],left[i] 是 A[i] 左边严格大于 A[i](>关系)的区间长度。right[i] 是 A[i] 右边非严格大于(>=关系)的区间长度。left[i] + 1 等于以 A[i] 结尾的子数组数目,A[i] 是唯一的最小值;right[i] + 1 等于以 A[i] 开始的子数组数目,A[i] 是第一个最小值。于是有 `f(i) = (left[i] + 1) * (right[i] + 1)`。例如对于 [3,1,4,2,5,3,3,1] 中的“2”,我们找到的串就为[4,2,5,3,3],2 左边有 1 个数比 2 大且相邻,2 右边有 3 个数比 2 大且相邻,所以 2 作为最小值的串有 2 * 4 = 8 种。用排列组合的思维也能分析出来,2 的左边可以拿 0,1,…… m 个,总共 (m + 1) 种,同理右边可以拿 0,1,…… n 个,总共 (n + 1) 种,所以总共 (m + 1)(n + 1)种。只要计算出了 f(i),这个题目就好办了。以 [3,1,2,4] 为例,left[i] + 1 = [1,2,1,1],right[i] + 1 = [1,3,2,1],对应 i 位的乘积是 f[i] = [1 * 1,2 * 3,1 * 2,1 * 1] = [1,6,2,1],最终要求的最小值的总和 res = 3 * 1 + 1 * 6 + 2 * 2 + 4 * 1 = 17。 +- **看到这种 mod1e9+7 的题目,首先要想到的就是dp**。最终的优化解即是利用 DP + 单调栈。单调栈维护数组中的值逐渐递增的对应下标序列。定义 `dp[i + 1]` 代表以 A[i] 结尾的子区间内最小值的总和。状态转移方程是 `dp[i + 1] = dp[prev + 1] + (i - prev) * A[i]`,其中 prev 是比 A[i] 小的前一个数,由于我们维护了一个单调栈,所以 prev 就是栈顶元素。(i - prev) * A[i] 代表在还没有出现 prev 之前,这些区间内都是 A[i] 最小,那么这些区间有 i - prev 个,所以最小值总和应该是 (i - prev) * A[i]。再加上 dp[prev + 1] 就是 dp[i + 1] 的最小值总和了。以 [3, 1, 2, 4, 3] 为例,当 i = 4, 所有以 A[4] 为结尾的子区间有: + + [3] + [4, 3] + [2, 4, 3] + [1, 2, 4, 3] + [3, 1, 2, 4, 3] + 在这种情况下, stack.peek() = 2, A[2] = 2。前两个子区间 [3] and [4, 3], 最小值的总和 = (i - stack.peek()) * A[i] = 6。后 3 个子区间是 [2, 4, 3], [1, 2, 4, 3] 和 [3, 1, 2, 4, 3], 它们都包含 2,2 是比 3 小的前一个数,所以 dp[i + 1] = dp[stack.peek() + 1] = dp[2 + 1] = dp[3] = dp[2 + 1]。即需要求 i = 2 的时候 dp[i + 1] 的值。继续递推,比 2 小的前一个值是 1,A[1] = 1。dp[3] = dp[1 + 1] + (2 - 1) * A[2]= dp[2] + 2。dp[2] = dp[1 + 1],当 i = 1 的时候,prev = -1,即没有人比 A[1] 更小了,所以 dp[2] = dp[1 + 1] = dp[-1 + 1] + (1 - (-1)) * A[1] = 0 + 2 * 1 = 2。迭代回去,dp[3] = dp[2] + 2 = 2 + 2 = 4。dp[stack.peek() + 1] = dp[2 + 1] = dp[3] = 4。所以 dp[i + 1] = 4 + 6 = 10。 +- 与这一题相似的解题思路的题目有第 828 题,第 891 题。 \ No newline at end of file diff --git a/README.md b/README.md index a5cb8d0f..f9d0abf9 100644 --- a/README.md +++ b/README.md @@ -950,7 +950,7 @@ | 0888 | Fair Candy Swap | | 56.80% | Easy | | | 0889 | Construct Binary Tree from Preorder and Postorder Traversal | | 60.30% | Medium | | | 0890 | Find and Replace Pattern | | 71.30% | Medium | | -| 0891 | Sum of Subsequence Widths | | 29.10% | Hard | | +| 0891 | Sum of Subsequence Widths |[Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0891.%20Sum%20of%20Subsequence%20Widths) | 29.10% | Hard | | | 0892 | Surface Area of 3D Shapes | | 56.10% | Easy | | | 0893 | Groups of Special-Equivalent Strings | | 62.80% | Easy | | | 0894 | All Possible Full Binary Trees | | 71.00% | Medium | | @@ -966,7 +966,7 @@ | 0904 | Fruit Into Baskets | [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0904.%20Fruit%20Into%20Baskets) | 41.60% | Medium | | | 0905 | Sort Array By Parity | | 72.60% | Easy | | | 0906 | Super Palindromes | | 30.40% | Hard | | -| 0907 | Sum of Subarray Minimums | | 27.60% | Medium | | +| 0907 | Sum of Subarray Minimums |[Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0907.%20Sum%20of%20Subarray%20Minimums) | 27.60% | Medium | | | 0908 | Smallest Range I | | 64.60% | Easy | | | 0909 | Snakes and Ladders | | 33.80% | Medium | | | 0910 | Smallest Range II | | 23.70% | Medium | | @@ -1247,8 +1247,8 @@ |[746. Min Cost Climbing Stairs](https://leetcode.com/problems/min-cost-climbing-stairs)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0746.%20Min%20Cost%20Climbing%20Stairs)| Easy | O(n)| O(1)|| |[766. Toeplitz Matrix](https://leetcode.com/problems/toeplitz-matrix)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0766.%20Toeplitz%20Matrix)| Easy | O(n)| O(1)|| |[867. Transpose Matrix](https://leetcode.com/problems/transpose-matrix)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0867.%20Transpose%20Matrix)| Easy | O(n)| O(1)|| -|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go]()| Hard | O(n)| O(1)|| -|[907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums)| [Go]()| Medium | O(n)| O(1)|| +|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0891.%20Sum%20of%20Subsequence%20Widths)| Hard | O(n log n)| O(1)|| +|[907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0907.%20Sum%20of%20Subarray%20Minimums)| Medium | O(n)| O(n)|| |[922. Sort Array By Parity II](https://leetcode.com/problems/sum-of-subarray-minimums)| [Go]()| Medium | O(n)| O(1)|| |[969. Pancake Sorting](https://leetcode.com/problems/pancake-sorting)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0969.%20Pancake%20Sorting)| Medium | O(n)| O(1)|| |[977. Squares of a Sorted Array](https://leetcode.com/problems/squares-of-a-sorted-array)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0977.%20Squares%20of%20a%20Sorted%20Array)| Easy | O(n)| O(1)|| @@ -1367,7 +1367,7 @@ |[880. Decoded String at Index](https://leetcode.com/problems/decoded-string-at-index)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0880.%20Decoded%20String%20at%20Index)| Medium | O(n)| O(n)|| |[895. Maximum Frequency Stack](https://leetcode.com/problems/maximum-frequency-stack)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0895.%20Maximum%20Frequency%20Stack)| Hard | O(n)| O(n) || |[901. Online Stock Span](https://leetcode.com/problems/online-stock-span)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0901.%20Online%20Stock%20Span)| Medium | O(n)| O(n) || -|[907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums)| [Go]()| Medium | O(n)| O(1)|| +|[907. Sum of Subarray Minimums](https://leetcode.com/problems/sum-of-subarray-minimums)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0907.%20Sum%20of%20Subarray%20Minimums)| Medium | O(n)| O(n)|| |[921. Minimum Add to Make Parentheses Valid](https://leetcode.com/problems/minimum-add-to-make-parentheses-valid)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0921.%20Minimum%20Add%20to%20Make%20Parentheses%20Valid)| Medium | O(n)| O(n)|| |[946. Validate Stack Sequences](https://leetcode.com/problems/validate-stack-sequences)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0946.%20Validate%20Stack%20Sequences)| Medium | O(n)| O(n)|| |[1003. Check If Word Is Valid After Substitutions](https://leetcode.com/problems/check-if-word-is-valid-after-substitutions)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/1003.%20Check%20If%20Word%20Is%20Valid%20After%20Substitutions)| Medium | O(n)| O(1)|| @@ -1450,7 +1450,7 @@ |[746. Min Cost Climbing Stairs](https://leetcode.com/problems/min-cost-climbing-stairs)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0746.%20Min%20Cost%20Climbing%20Stairs)| Easy | O(n)| O(1)|| |[838. Push Dominoes](https://leetcode.com/problems/push-dominoes)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0838.%20Push%20Dominoes)| Medium | O(n)| O(1)|| |[1025. Divisor Game](https://leetcode.com/problems/divisor-game)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/1025.%20Divisor%20Game)| Easy | O(1)| O(1)|| -|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go]()| Hard | O(n)| O(1)|| +|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0891.%20Sum%20of%20Subsequence%20Widths)| Hard | O(n log n)| O(1)|| |[942. DI String Match](https://leetcode.com/problems/di-string-match)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0942.%20DI%20String%20Match)| Easy | O(n)| O(1)|| |-----------------------------------------------------------------|-------------|-------------| --------------------------| --------------------------|-------------| @@ -1568,7 +1568,7 @@ |[357. Count Numbers with Unique Digits](https://leetcode.com/problems/count-numbers-with-unique-digits)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0357.%20Count%20Numbers%20with%20Unique%20Digits)| Medium | O(1)| O(1)|| |[628. Maximum Product of Three Numbers](https://leetcode.com/problems/maximum-product-of-three-numbers)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0628.%20Maximum%20Product%20of%20Three%20Numbers)| Easy | O(n)| O(1)|| |[885. Spiral Matrix III](https://leetcode.com/problems/spiral-matrix-iii)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0885.%20Spiral%20Matrix%20III)| Medium | O(n^2)| O(1)|| -|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go]()| Hard | O(n)| O(1)|| +|[891. Sum of Subsequence Widths](https://leetcode.com/problems/sum-of-subsequence-widths)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0891.%20Sum%20of%20Subsequence%20Widths)| Hard | O(n log n)| O(1)|| |[942. DI String Match](https://leetcode.com/problems/di-string-match)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0942.%20DI%20String%20Match)| Easy | O(n)| O(1)|| |[976. Largest Perimeter Triangle](https://leetcode.com/problems/largest-perimeter-triangle/)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0976.%20Largest%20Perimeter%20Triangle)| Easy | O(n log n)| O(log n) || |[996. Number of Squareful Arrays](https://leetcode.com/problems/number-of-squareful-arrays)| [Go](https://github.com/halfrost/LeetCode-Go/tree/master/Algorithms/0996.%20Number%20of%20Squareful%20Arrays)| Hard | O(n log n)| O(n) ||