leetcode - [题型总结] - K-Sum问题

本文详细介绍了LeetCode中的K-Sum问题,包括问题类型特征、通用解题思路及多个实例,如Two Sum II、Two Sum、3Sum、3Sum Closet、3Sum Smaller和4Sum。解题方法主要涉及排序、哈希表和双指针等技术,旨在通过不同K值的求和问题,提升算法思维和解决实际问题的能力。

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

1、问题类型特征

从数组中找出K个数,使得这K个数的和与target满足一定的关系。

2、通用解题思路

  • 暴力解法:使用K层循环,最常见,但是效率极低;
  • hash-map:建立一个hash-map循环遍历一次即可,这个方法适用于K=2的情况。
  • two-pointers:先对数组进行排序,然后使用K-2重循环固定K-2个数,最后使用双指针寻找剩下的2个数,这种方法的时间复杂度为 O ( n K − 1 ) O(n^{K-1}) O(nK1)

3、问题实例

Leetcode中属于该类型的题目:

序号题目问题难度
1Two Sumeasy
167Two Sum II-Input array is sortedeasy
153Summedium
163Sum Closetmedium
2593Sum Smallermedium
184Summedium
(1)Two Sum II-Input array is sorted
(2)Two Sum
  • 问题描述
    输入一个数组和数target,从数组中找出两个数,使得这两个数的和等于target。
  • 解题思路
  • 思路1:有了问题(1)的基础,我们就可以先对数组进行排序,然后再找出和为target的两个数。如果题目要求只是找到这两个数,直接返回即可;但如果要求返回这两个数在原数组中的索引,由于对原数组进行排序会打乱原数组中元素的顺序,所以需要使用一个额外的数据结构(哈希表,结构体,或类)记录元素在原数组中的索引。这种方法花费的时间主要在排序上,所以时间复杂度为 O ( n ) O(n) O(n),如果最终返回的是索引,那么空间复杂度为 O ( n ) O(n) O(n)
  • 思路2:还有一种时间复杂度为 O ( n ) O(n) O(n),空间复杂度为 O ( n ) O(n) O(n)的方法。这种方法的基本思路是采用哈希表来记录每个数的相反数的索引,从头到尾遍历数组,每遍历一个数,看哈希表的键集合中是否包含该数,如果包含,则可以直接得到它相反数的索引,如果不包含,则将(它的相反数,它自身的索引)作为键值对插入哈希表。
  • 代码实现
def TwoSum(array, target):
    """
    :type array:list[int]
    :type targt:int
    :rtype list[tuple]
    """
    if len(array) == 0 or array == None:
        return None
    oppsite = {}
    twosum = []
    for (i,element) in enumerate(array):
        if element in oppsite.keys():
            twosum.append((oppsite[element],i))
            
        else:
            oppsite[target - element] = i

    return twosum

(3)3Sum
  • 问题描述
    输入一个数组和一个数target,从数组中找出三个数,使得这三个数的和为target。找出所有满足条件且不重复的三元组。
  • 解题思路
  • 思路1:首先对数组进行排序,然后用一个循环固定一个数,之后再使用双指针,从该数后面的所有数查找两个数,使得这两个数之和等于target。由于不能包含重复的三元组,所以在外层循环遍历和内层双指针查找的时候,都要去除重复的元素。这种方法的时间复杂度为 O ( n 2 ) O(n^{2}) O(n2)
  • 代码实现
def ThreeSum(array, target):
    """
    :type array:list[int]
    :type targt:int
    :rtype list[tuple]
    """

    if len(array) < 3 or array == None :
        return None

    result = []

    array = sorted(array)

    for i in range(0,len(array)):
        if i > 0 and array[i] == array[i-1]:
            continue
        
        start = i + 1
        end = len(array) - 1
        while start < end:
            sum = array[start] + array[end] + array[i]
            
            if sum == target:
                result.append((array[i],array[start],array[end]))
                start += 1
                end -= 1
                
                while start < end and array[start] == array[start -1]:
                    start += 1
                while start < end and array[end] == array[end + 1]:
                    end -= 1
            elif sum < target:
                start += 1
            else:
                end -= 1

    return result 
(4)3Sum Closet
  • 问题描述
    输入一个数组和数target,从数组中找出三个数,使这三个之和最接近target。
  • 解题思路
  • 思路1:这道题是3sum问题的简单变形。3sum问题是要求三个数的和与target的差值为0,而3Sum Closet问题则是要求三个数的和与target的差值的绝对值尽可能接近0。所以,只需要稍加修改3Sum问题的代码,即可实现3Sum Closet问题的求解。同样是先对数组进行排序,接着使用一个循环固定一个数,然后使用双指针在固定的数后面寻找另外两个数,在两个指针相遇前,每次都计算外层循环和双指针指向的三个数之和,并使用变量closet记录三数之和与target的差值的绝对值,若本次得到的closet比上次小,则对closet进行更新,否则不更新。之后,比较三数之和与target的大小,如果小于target,则前面的指针向后移动,如果大于target,则后面的指针向前移动。
  • 代码实现
def ThreeSumCloset(array, target):
    """
    :type array:list[int]
    :type targt:int
    :rtype list[tuple]
    """

    if len(array) < 3 or array == None :
        return None

    result = None

    array = sorted(array)
    closet = abs(sum(array[:3]) - target)

    for i in range(0,len(array)):
        if i > 0 and array[i] == array[i-1]:
            continue
   
        start = i + 1
        end = len(array) - 1
        while start < end:
            sum_ = array[start] + array[end] + array[i]
            if sum_ == target:
                result = (array[i],array[start],array[end])
                return result
            
            diff = abs(sum_ - target)

            if diff < closet:
                closet = diff 
                result = (array[i],array[start],array[end])
                    
            while  start < end and array[start] == array[start - 1]:
                start += 1
            while start < end and end < len(array) - 1 and array[end] == array[end + 1]:
                end -= 1
            
      
            if sum_ < target:
                start += 1
            elif sum_ > target:
                end -= 1

    return result 
(5)3Sum Smaller
  • 问题描述
    输入一个整数数组array和整数target,从数组array中找到这样的索引三元组(i,j,k),使得array[i] 、array[j] 、array[k]之和小于target,同时满足i < j < k。求这样的三元组的数量。
  • 解题思路
  • 思路1:和问题(3)、(4)是一样的思路。
  • 代码实现
def ThreeSumCloset(array, target):
    """
    :type array:list[int]
    :type targt:int
    :rtype list[tuple]
    """

    if len(array) < 3 or array == None :
        return None

    result = []
    array = sorted(array)


    for i in range(0,len(array)):
        if i > 0 and array[i] == array[i-1]:
            continue
   
        start = i + 1
        end = len(array) - 1
        while start < end:
            sum_ = array[start] + array[end] + array[i]
                    
            while start < end and array[start] == array[start - 1]:
                start += 1
            while start  < end and end < len(array) - 1 and array[end] == array[end + 1]:
                end -= 1     
      
            if sum_ < target:
            	result.append((i, start,end))
                start += 1
            elif sum_ > target:
                end -= 1

    return len(result) 
(6)4Sum
  • 问题描述
    给出一个整数数组和目标数target,从中找到所有可能的4个数,使得这四个数的和等于目标数。注意不能有重复的情况。
  • 解题思路:
    *思路1: 这道题可以才有用与3sum同样的思路。只不过需要外部需要使用两层循环来固定两个数。时间复杂度为 O ( n 3 ) O(n^{3}) O(n3)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Albert_YuHan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值