每一日练 43--51 前缀和

本文通过43到51道LeetCode题目,介绍如何利用前缀和解决数组中出现次数的问题,涉及单元素出现一次的查找、字符串长度乘积最大值、连续子数组和等算法问题,讲解了滑动窗口、排序、位运算等多种解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用前面的值的和推算后面的值就是前缀和

43 

力扣https://leetcode-cn.com/problems/WGki4K/

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

思路:可以使用map,也可以使用位数,一定出现三次会导致位一定被3整除,剩下的就是多余的值

func singleNumber(nums []int) int {
	nummap:=make(map[int]int)
	for i:=0;i<len(nums);i++{
		nummap[nums[i]]++
	}
	for k,v:=range nummap{
		if v==1{
			return k
		}
	}
	return -1
}

44

力扣https://leetcode-cn.com/problems/aseY1I/

给定一个字符串数组 words,请计算当两个字符串 words[i] 和 words[j] 不包含相同字符时,它们长度的乘积的最大值。假设字符串中只包含英语的小写字母。如果没有不包含相同字符的一对字符串,返回 0。

思路:按位与的思路,如果两个单词没有重复单词,那么按位与的结果就是0

func SameMapV2(a,b int)bool{
	return a&b>0
}

func maxProduct(words []string) int {
	var length int
	//每个单词的字符组合
	varmap:=make(map[string]int)
	for i:=0;i<len(words);i++{
		var tmp int
		for j:=0;j<len(words[i]);j++{
			tmp |= 1<<(words[i][j]-'a')
		}
		varmap[words[i]] = tmp
		for z:=i-1;z>=0;z--{
			if !SameMapV2(varmap[words[i]],varmap[words[z]]){
				//如果两个单词不重复
				tmp := len(words[i])*len(words[z])
				if tmp > length{
					length = tmp
				}
			}
		}
	}
	return length
}

45

力扣https://leetcode-cn.com/problems/kLl5u1/

给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 0 开始计数 ,所以答案数组应当满足 0 <= answer[0] < answer[1] < numbers.length 。假设数组中存在且只存在一对符合条件的数字,同时一个数字不能使用两次。

思路:升序,双指针,一个从前,一个从后

func twoSum(numbers []int, target int) []int {
	start:=0
	end:=len(numbers)-1
	for start<end{
		tmp:=numbers[start] + numbers[end]
		if tmp ==target{
			return []int{start,end}
		}else if tmp < target{
			start++
		}else{
			end--
		}
	}
	return nil
}

46

力扣https://leetcode-cn.com/problems/1fGaJU/

给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a ,b ,c ,使得 a + b + c = 0 ?请找出所有和为 0 且 不重复 的三元组。

思路:先排序,所谓的a+b+c=0就是确定一个值从剩下的找出两个数的和=target

func threeSum(nums []int) [][]int {
	if len(nums) < 3 {
		return nil
	}
	var res [][]int
	sort.Ints(nums)
	for i := 0; i < len(nums); i++ {
		if i >= 1 && nums[i] == nums[i-1] {
			continue
		}
		target := nums[i]
		start := i + 1
		end := len(nums) - 1
		indexmap := make(map[string]bool)
		for start < end {
			tmp := nums[start] + nums[end]
			if tmp == -target {
				ss := strconv.Itoa(nums[start])
				se := strconv.Itoa(nums[end])
				if !indexmap[ss+"_"+se] {
					indexmap[ss+"_"+se] = true
					res = append(res, []int{target, nums[start], nums[end]})
				}
				start++
				end--
			} else if tmp < -target {
				start++
			} else {
				end--
			}
		}
	}
	return res
}

47

力扣https://leetcode-cn.com/problems/2VG8Kg/

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

思路:滑动窗口的方式保证一次遍历的速度

func minSubArrayLen(target int, nums []int) int {
	var sum,res int
	start:=0
	//不能排序
	for i:=0;i<len(nums);i++{
		sum = sum + nums[i]
		for sum>=target{
			tmp := i - start + 1
			if res ==0{
				res = tmp
			}else if res > tmp{
				res = tmp
			}
			sum = sum - nums[start]
			start++
		}
	}
	return res
}

48

力扣https://leetcode-cn.com/problems/ZVAVXX/

给定一个正整数数组 nums和整数 k ,请找出该数组内乘积小于 k 的连续的子数组的个数。

思路:滑动窗口,一看到连续的,且全部都是一个顺序,就说明连续子窗口是可以串联起来的,如果i--j不可以,那么不存在i--n(n>j)可以,就要想到滑动窗口这一思路

func calculate(nums []int) int {
	res := nums[0]
	for i := 1; i < len(nums); i++ {
		res = res * nums[i]
	}
	return res
}

func numSubarrayProductLessThanK(nums []int, k int) int {
	var sum int
	var left,right int
	for left < len(nums){
		for right<len(nums)&&calculate(nums[left:right+1]) < k {
			right++
		}
		sum = sum + right - left
		left = left + 1
		if right<left{ 
			right = left
		}
	}
	return sum
}

49

力扣https://leetcode-cn.com/problems/QTMn0o/

给定一个整数数组和一个整数 k ,请找到该数组中和为 k 的连续子数组的个数。

思路:第一想法是滑动窗口,但是由于是整数,存在负数的可能性,如果i--j不可以,存在i--n(n>j)可以,用滑动窗口就得遍历每一个终点时间复杂度O(n),所以放弃,我们希望可以以o(n)解决,就可以使用前缀算法

func subarraySum(nums []int, k int) int {
    var res,sum int
    hashmap:=make(map[int]int)
    //使用前缀和算法
    //当存在前缀x == sum - k说明一个连续子数组满足条件
    //如果sum-k==0说明刚好成立,因此hashmap[0] = 1
    hashmap[0] = 1
    for i:=0;i<len(nums);i++{
        sum = sum + nums[i]
        res = res + hashmap[sum-k]
        hashmap[sum]++
    }
    return res
}

50

力扣https://leetcode-cn.com/problems/A1NYOS/给定一个二进制数组 nums , 找到含有相同数量的 0 和 1 的最长连续子数组,并返回该子数组的长度。

func findMaxLength(nums []int) int {
	var res int
	var cnt int
	hashMap := make(map[int]int)
	hashMap[0] = -1
	for i, num := range nums {
		if num == 0 {
			cnt--
		} else {
			cnt++
		}
		if v, has := hashMap[cnt]; has {
			res = max(res, i-v)
		} else {
			hashMap[cnt] = i
		}
	}
	return res
}
func max(a, b int) int {
	if a > b {
		return a
	}
	return b
}

51

 https://leetcode-cn.com/problems/A1NYOS/https://leetcode-cn.com/problems/A1NYOS/

给你一个整数数组 nums ,请计算数组的 中心下标 。

数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。

如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。

如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。

思路:充分利用条件,左边和等于右边和,则有sum*2+nums[i]==total成立,return i

//采用前缀和思路,要找下标只需要找到坐标i,使得
//nums[0:i] == nums[i+1:]
func pivotIndex(nums []int) int {
  var total int
  for i:=0;i<len(nums);i++{
      total = total + nums[i]
  }
  var sum int 
  for i:=0;i<len(nums);i++{
      if sum*2+nums[i]==total{
          return i
      }    
      sum = sum + nums[i]
  }
  return -1
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值