leetcode - 1679 - K 和数对的最大数目

题目描述

[1679] K 和数对的最大数目

给你一个整数数组 nums 和一个整数 k 。

每一步操作中,你需要从数组中选出和为 k 的两个整数,并将它们移出数组。

返回你可以对数组执行的最大操作数。

示例 1:

输入:nums = [1,2,3,4], k = 5
输出:2
解释:开始时 nums = [1,2,3,4]:

  • 移出 1 和 4 ,之后 nums = [2,3]
  • 移出 2 和 3 ,之后 nums = []
    不再有和为 5 的数对,因此最多执行 2 次操作。
    示例 2:

输入:nums = [3,1,3,4,3], k = 6
输出:1
解释:开始时 nums = [3,1,3,4,3]:

  • 移出前两个 3 ,之后nums = [1,4,3]
    不再有和为 6 的数对,因此最多执行 1 次操作。

提示:

  • 1 <= nums.length <= 10^5
  • 1 <= nums[i] <= 10^9
  • 1 <= k <= 10^9
Related Topics
  • 数组
  • 哈希
  • 双指针

题目剖析&信息挖掘

题目是要找到和为k的数对,可以用哈希法和双指针法解决

解题思路

根据题意一个数字用完后会删除,所以一个数字最多只用一次。利用贪心原理,去遍历数组,找到另一个数字并从中删除。这就转化成从数组中找出和为k的对数。和之前的两数之和、三数之和、四数之和的题类似。有2种做法一种是直接哈希法,另一种是排序以后用双指针法。

方法一 哈希法

思路
  • 维护哈希表存储数字的个数
  • 遍历数组,对于遍历的数字n,查看前面有没与之加和为k的数
  • 如果有就删除k-n,并sum++,如果没有就把n加入到哈希表中。
func maxOperations(nums []int, k int) int {
  m:= make(map[int]int, len(nums)) //
	sum := 0
	for _, n:= range nums {
		if m[n]>0 {
			sum++
			m[n]--
		} else {
			m[k-n]++ // 这里存储的相减后的结果 
		}
	}
	return sum
}
注意
  • 哈希设计要用统计,不能用bool
  • 同种组合有多组的情况, 如[3,3,3,3] , 6
知识点
  • 数组
  • 哈希
复杂度
  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
代码实现
func maxOperations(nums []int, k int) int {
  m:= make(map[int]int, len(nums)) //
	sum := 0
	for _, n:= range nums {
		if m[n]>0 {
			sum++
			m[n]--
		} else {
			m[k-n]++ // 这里存储的相减后的结果 
		}
	}
	return sum
}

方法二 双指针法

思路
  • 先对数组排序
  • 用双指针对头尾进行遍历
func maxOperations(nums []int, k int) int {
  sort.Sort(nums)
	sum := 0
  left, right := 0, len(nums)-1
  // nums[left]<nums[right]
	for ;left<right; {
    if nums[left]+nums[right] == k {
      sum++
      left++
      right--
    } else if nums[left]+nums[right] < k { // 说明小的数字要增大
      left++
    } else { // 大的数字要减少
      right--
    }
	}
	return sum
}
注意
  • 一定要先排序
  • 同种组合有多组的情况, 如[3,3,3,3] , 6
知识点
  • 数组
  • 双指针
  • 排序
复杂度
  • 时间复杂度:O(nlog(n))
  • 空间复杂度:O(n)
参考
代码实现
func maxOperations(nums []int, k int) int {
	sort.Sort(sort.IntSlice(nums))
	sum := 0
	left, right := 0, len(nums)-1
	// nums[left]<nums[right] 恒成立
	for ;left<right; {
		if nums[left]+nums[right] == k {
			sum++
			left++
			right--
		} else if nums[left]+nums[right] < k { // 说明小的数字要增大才有可能使和=k
			left++
		} else { // 大的数字要减少,同理。
			right--
		}
	}
	return sum
}

相关题目

https://leetcode-cn.com/problems/two-sum/

https://leetcode-cn.com/problems/3sum/

https://leetcode-cn.com/problems/4sum/
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值