面对恐惧day7

今天补了上上次的最后一道题和昨天的全部,“正经人谁写日记啊”,以下是正正经经的day7。

第454题.四数相加II

​​​​​​力扣题目链接

所思所想:

1.这道题很特别,运用了分治法的思想,我认为暴力法的时间复杂度是n的4次方,但代码随想录认为是3次方,也有可能是我错了,欢迎大家指正,但是改进版是n的平方,我也如此认为。

2.具体做法就是把四个数组分为两组,ab,cd各一组,将ab组遍历得到各种可能加和的哈希表,再带着该哈希表,去遍历cd。

3.由于题目本身要求,返回值是所有可能满足加和为target的排列组合的个数(所以在算ab组的哈希表时,计数是必要的)

答案如下:

class Solution(object):
    def fourSumCount(self, nums1, nums2, nums3, nums4):
        table = {}
        for num1 in nums1:
            for num2 in nums2:
                table[num1 +num2] = table.get(num1 +num2,0) + 1
        count = 0
        for num3 in nums3:
            for num4 in nums4:
                if -(num3 +num4) in table:
                    count+=table[-num3-num4]
        return count

但其实我第一遍做错了,虽然验证过了,但是一提交复杂的例子没过,原因在于倒数第二行我写的是:

count+=1

而答案应该是:

count+=table[-num3-num4]

区别在于,最后统计的是不同排列组合。

第15题. 三数之和

力扣题目链接

个人认为这题比较讨人厌,不想深度思考了,答案用了三指针的方法,理解性默写一遍就得了。

1.返回结果过早:在找到一组和为 0 的三元组后,代码直接使用 return 语句返回该三元组,而没有继续寻找其他可能的三元组。

2.未处理重复元素:代码没有处理列表中可能存在的重复元素,这可能会导致结果中出现重复的三元组。

3.返回 [] 的位置有误:代码在当前 index 对应的循环结束后就直接返回 [],这意味着只会检查第一个元素,而不会继续检查后续元素

这是豆包给我原创代码的修改意见,非常切中要害。

class Solution(object):
    def threeSum(self, nums):
        result =[]
        nums.sort()
        for i in range(len(nums)):
            left = i+1
            right = len(nums)-1
            if nums[i] > 0:
                return result
            elif i>0 and nums[i] == nums[i-1]:
                continue
            while left <right:
                if nums[i]+nums[left]+nums[right]<0:
                    left+=1
                elif nums[i]+nums[left]+nums[right]>0:
                    right-=1
                elif nums[i]+nums[left]+nums[right]==0:
                    result.append([nums[i],nums[left],nums[right]])
                    while left <right and nums[left]==nums[left+1]:
                        left+=1
                    while left <right and nums[right]==nums[right-1]:
                        right-=1
                    left+=1
                    right-=1
                
        return result

对于这个正确答案,我改了好几遍,有以下几个改动点值得反思

1.elif i > 0 这句很重要,直接影响了【0,0,0】等相同特点的元组,反过来说,也会越界,但没报错,不知道为什么。

2.这道题其实最主干的思想在最后一个elif中,这段代码百分之八十的字符数都在做剪枝操作。

383. 赎金信

力扣题目链接

之前的哈希表都是偏理论,这题算是一个结合实际的小应用题,挺有意思,也很简单,昭示了哈希表的应用场景。

第18题. 四数之和

力扣题目链接

class Solution(object):
    def fourSum(self, nums, target):
        result =[]
        nums.sort()
        length=len(nums)
        for i in range(length):
            if i > 0 and nums[i]==nums[i-1]:
                continue
            for j in range(i+1, length):
                if j > i+1 and nums[j]==nums[j-1]:
                    continue
                left = j + 1
                right = length -1
                while left < right:
                    sum = nums[i]+nums[j]+nums[left]+nums[right]
                    if sum < target:
                        left+=1
                    if sum > target:
                        right-=1
                    if sum == target:
                        result.append([nums[i],nums[j],nums[left],nums[right]])
                        while left<length-1 and nums[left]==nums[left+1]:
                            left+=1
                        left+=1
                        while right>=0 and nums[right]==nums[right-1]:
                            right-=1
                        right-=1
        return result

我尽可能没有用剪枝操作,展现了必要过程,而没有追求极致的运行时间。

对于这段代码我有几个思考:

1.

if i > 0 and nums[i] == nums[i-1]:# 去重
    continue
if j > i+1 and nums[j] == nums[j-1]: # 去重
    continue

在思考这两句的时候,我觉得应该换一种perspective,不要去考虑大于多少多少就不行了,而是相同的数就放参与组合一次,也就是只有i=0,j=i-1,再加上后边的条件会导致continue也就是跳过。

2.

while left < right and nums[left] == nums[left+1]:
    left += 1
while left < right and nums[right] == nums[right-1]:
    right -= 1

答案是这么写的,首先第一遍写的时候我压根就没想通该怎么去重,单看答案之后觉得很疑惑,为什么呢?left<right为什么是判断条件,其实是反直觉的,因为一整个大循环体的准入条件就是left<right,但这道题让我体会到,这两者并没有直接关系,因为left,right的值靠的是语句,不是自动的。而且这里其实暗含了一种剪枝。

while left<length-1 and nums[left]==nums[left+1]:
    left+=1
left+=1
while right>=0 and nums[right]==nums[right-1]:
    right-=1
right-=1

这样才是纯去重,上边其实有点添油加醋了,但添油加醋可以少循环几次,节省时间。

总结

这章说是哈希,但其实哈希理解了以后,至少这几道不难,但是三数之和和四数之和用指针,很复杂,首先去重的逻辑不简单,其次考虑剪枝更复杂,还需熟能生巧。辛苦了!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值