mirror of
https://gitlab.com/game-loader/hugo.git
synced 2025-04-20 05:52:07 +08:00
leetcode update
This commit is contained in:
parent
9c17cebab9
commit
5c5f32bd0a
@ -1042,3 +1042,177 @@ func pivotInteger(n int) int {
|
|||||||
### 总结
|
### 总结
|
||||||
|
|
||||||
查看他人解法发现本题其实也可以使用前缀和进行求解, 将每个下标位置处的前缀和求出并保存, 倒序遍历数组, 将后面的数的和与当前位置的前缀和比较即可, 示例代码
|
查看他人解法发现本题其实也可以使用前缀和进行求解, 将每个下标位置处的前缀和求出并保存, 倒序遍历数组, 将后面的数的和与当前位置的前缀和比较即可, 示例代码
|
||||||
|
|
||||||
|
## day17 2024-03-14
|
||||||
|
|
||||||
|
### 930. Binary Subarrays With Sum
|
||||||
|
|
||||||
|
Given a binary array nums and an integer goal, return the number of non-empty subarrays with a sum goal.
|
||||||
|
|
||||||
|
A subarray is a contiguous part of the array.
|
||||||
|
|
||||||
|
Example 1:
|
||||||
|
|
||||||
|
Input: nums = [1,0,1,0,1], goal = 2
|
||||||
|
Output: 4
|
||||||
|
Explanation: The 4 subarrays are bolded and underlined below:
|
||||||
|
[1,0,1,0,1]
|
||||||
|
[1,0,1,0,1]
|
||||||
|
[1,0,1,0,1]
|
||||||
|
[1,0,1,0,1]
|
||||||
|
Example 2:
|
||||||
|
|
||||||
|
Input: nums = [0,0,0,0,0], goal = 0
|
||||||
|
Output: 15
|
||||||
|
|
||||||
|
### 题解
|
||||||
|
|
||||||
|
本题可以用前缀和求解, 类似这种求数组中连续和的问题都可以用前缀和求解, 首先计算出所有位置上的前缀和, 使用滑动窗口遍历前缀和数组, 根据goal的值调整窗口的左右边界, 注意0需要特殊处理, 0是否存在不影响整个序列的和, 0所在的位置处的前缀和和前面的元素相同.
|
||||||
|
|
||||||
|
### 代码
|
||||||
|
|
||||||
|
```go
|
||||||
|
func numSubarraysWithSum(nums []int, goal int) int {
|
||||||
|
|
||||||
|
sum := 0
|
||||||
|
|
||||||
|
prefixsum := []int{0}
|
||||||
|
|
||||||
|
for _,value := range nums{
|
||||||
|
|
||||||
|
sum += value
|
||||||
|
|
||||||
|
prefixsum = append(prefixsum, sum)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
front := 1
|
||||||
|
|
||||||
|
back := 0
|
||||||
|
|
||||||
|
flag := 0
|
||||||
|
|
||||||
|
result := 0
|
||||||
|
|
||||||
|
for front < len(prefixsum){
|
||||||
|
|
||||||
|
if prefixsum[front] - prefixsum[back]<goal{
|
||||||
|
|
||||||
|
front++
|
||||||
|
|
||||||
|
}else if prefixsum[front] - prefixsum[back]>goal{
|
||||||
|
|
||||||
|
if front-1 == back{
|
||||||
|
|
||||||
|
front++
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
back++
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
if (front-1 == back){
|
||||||
|
|
||||||
|
result++
|
||||||
|
|
||||||
|
front++
|
||||||
|
|
||||||
|
back = flag
|
||||||
|
|
||||||
|
}else if prefixsum[back] == prefixsum[back+1]{
|
||||||
|
|
||||||
|
result++
|
||||||
|
|
||||||
|
back++
|
||||||
|
|
||||||
|
}else if (front<len(prefixsum)-1) && prefixsum[front] == prefixsum[front+1]{
|
||||||
|
|
||||||
|
result++
|
||||||
|
|
||||||
|
front++
|
||||||
|
|
||||||
|
back = flag
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
|
result++
|
||||||
|
|
||||||
|
back++
|
||||||
|
|
||||||
|
flag=back
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 总结
|
||||||
|
|
||||||
|
本题使用滑动窗口时间复杂度上比较高, 考虑在滑动窗口的过程中, 连续的0的部分被重复遍历, 大大增加了总体的运行时间. 其实本题只需要用当前的前缀和减去goal, 并寻找前面的前缀和中是否有符合差值的前缀和存在, 存在则从该前缀和位置到当前前缀和位置直接的序列满足和为goal的条件. 已经求出了前缀和就没必要再去一个个遍历并且滑动了, 如果使用滑动窗口则没必要计算前缀和. 我的解法实际上是对前缀和理解不深刻导致的. 巧用前缀和加哈希表(存储某个前缀和出现的次数)可以快速的解决这个问题. 示例代码如下
|
||||||
|
|
||||||
|
```go
|
||||||
|
func numSubarraysWithSum(nums []int, goal int) int {
|
||||||
|
hash := map[int]int{}
|
||||||
|
sum := 0
|
||||||
|
count := 0
|
||||||
|
hash[0] = 1
|
||||||
|
for i:=0; i < len(nums); i++ {
|
||||||
|
sum = sum + nums[i]
|
||||||
|
count = count + hash[sum - goal]
|
||||||
|
val, ok := hash[sum]
|
||||||
|
if(ok) {
|
||||||
|
hash[sum] = val + 1
|
||||||
|
} else {
|
||||||
|
hash[sum] = 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
还有一种极其巧妙的解法, 分别求得和小于等于goal的连续子序列的数量, 再减去和小于等于goal-1的连续子序列的数量即为最终结果. 本题中求子序列等于goal是比较困难的, 要考虑很多条件, 但是求小于等于goal的子序列却是比较简单的问题. 这种方法将一个困难问题转化为两个简单的子问题求解, 得到了更高效的方法. 充分利用整体性可使问题更简单. 代码如下
|
||||||
|
|
||||||
|
```go
|
||||||
|
func numSubarraysWithSum(nums []int, goal int) int {
|
||||||
|
|
||||||
|
return counting(nums, goal) - counting(nums, goal-1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func counting(nums []int, goal int) int {
|
||||||
|
|
||||||
|
if goal < 0 {
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
left, right, sum, ans := 0, 0, 0, 0
|
||||||
|
|
||||||
|
for ; right < len(nums); right++ {
|
||||||
|
|
||||||
|
sum += nums[right]
|
||||||
|
|
||||||
|
for left <= right && sum > goal {
|
||||||
|
|
||||||
|
sum -= nums[left]
|
||||||
|
|
||||||
|
left++
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ans += right - left + 1
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return ans
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user