leetcode update

This commit is contained in:
gameloader 2024-03-14 11:30:50 +08:00
parent 9c17cebab9
commit 5c5f32bd0a

View File

@ -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
}
```