代码随想录算法训练营|day6| Leetcode454/383/15/18

Leetcode454 四数相加II

链接:454. 四数相加 II - 力扣(LeetCode)

这里是用哈希的方式来解决,首先我们对前两个数组分别进行一个循环并且用一个dict把他们的值保存起来,value用来记录

    既然是四个数相加等于0 那我们的0如果减去后两个数组中元素的和 是不是就等于前两个数组了!

  并且这里是要返回有几个数字的组合,那value就是用来记录前两个数组元素的和出现的次数

    如果在0减去了后两个数组中的和,已经出现在dict中了,那就说明当前循环到的数字和之前保存下来的可以凑成一整对

    可能这里就有疑惑 为什么这里value不是直接+=1呢

    举个例子:a1 a2

                      b1 b3

                      c1 c3

                      d1 d3

    我们假设dict中:{5:3:}经过两次for循环之后是存了这些

    这个5可能是a1+b1/a2+b3/a1+b3得到的值,出现了3次

    如果之后的循环中发现 c1+d3 = 5,那此时有几种组合?

    那是不是(a1,b1,c1,d3)

                     (a2,b3,c1,d3)

                     (a1,b3,c1,d3)

    是不是就有3种了

    所以value应该+=该值出现的次数

代码:

hashmap = dict()
        value  = 0 

        for i in range(0,len(nums1)):
            for j in range(0,len(nums2)):
                if nums1[i]+nums2[j] not in hashmap:
                    hashmap[nums1[i]+nums2[j]] = 1
                else:
                    hashmap[nums1[i]+nums2[j]] += 1

        for x in range(0,len(nums3)):
            for y in range(0,len(nums4)):
                if 0-(nums3[x]+nums4[y]) in hashmap:
                    value +=hashmap[-nums3[x]-nums4[y]]
        return value

Leetcode383赎金信

链接:383. 赎金信 - 力扣(LeetCode)

思路:首先这道题一个暴力的解决思路就是map到数组上记录每个字母出现的次数,创建一个结果数组储存。首先循环我们的magazine字符串。把每个字母的accssi码和第一个字母'a'进行一个相减的操作得到一个相对位置。也就相当于是我们当前字母出现次数了!然后循环我们的ransomnote字符串,同样的用每个字母的accsii码去减掉第一个字母'a'的accsii码!这里需要注意一下 我们是直接再record数组中记录我们的次数。最后我们循环结果数组,如果说里面的数字<0.那就说明有多余的字母了!所以这里被剪完了才会导致小于0出现,然后就可以返回false了,最后循环完毕 返回true.

代码:

if len(ransomNote)>len(magazine):
            return False
        record = [0] * 26 
        for i in range(len(magazine)):
            record[ord(magazine[i]) - ord('a')]+=1
        for j in range(len(ransomNote)):
            record[ord(ransomNote[j])-ord('a')]-=1
        
        for x in range(len(record)):
            if record[x]<0:
                return False
        return True

Leetcode15三数之和

链接:15. 三数之和 - 力扣(LeetCode)

首先明确一点,这里的重复元组并不是代表元素不能重复!例如(0,0,0)

代码:

def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []
        nums.sort()
        for i in range(len(nums)):
            left = i+1 
            right = len(nums)-1 
            if nums[i]>0:
                break
            #如果说第一个数字都大于0了,那么之后的数字相加也不可能小于0,因为数组是经过排序了的
            if i>0 and nums[i]==nums[i-1]:
                continue
            #这里为什么不是<=,因为这里我们的left==right指向了同一个元素,题目是要三个有效数字,但是这里只有两个,所以不取=
            while left<right:
                #记录当前三个数的和
                total = nums[i] + nums[left] + nums[right]
                #判断是否为结果数组
                if total>0:
                    right-=1 
                elif total<0:
                    left+=1
                else:
                    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]:
                    #如果当前都是满足题目要求且其余两个数字没有重复,那我们才继续将left指针和right指针向中间移动
                        right-=1 
                    left+=1
                    right-=1
        return result 

第一步: 

这里首先对数组进行了一个排序,排序完之后,我们可以判断第一个数字,如果说第一个数字都大于0了,那么后面的数字再怎么加也不会等于0,因为我们数组已经排过序了。所以如果第一个数字>0,那我们直接就break掉了不对当前这个数字做检查。

第二步:

              这里注意一下是while left<right而不是<=。因为当我们left与right指向同一个元素时是没有意义的。我们需要的是三个数组成的元组,但是他们只有两个数。所以不能取等

 然后对第一个数字进行去重,也就是判断nums[I]= or!=nums[i-1].这里为什么不写成i+1呢??

举个例子:-1,-1,2

如果是是i+1的话,首先i=0,那么i+1 =就是第一个指针

第一题数字为-1.直接判断下一个元素也是-1,那我们的结果集就会直接pass掉所以就收取不到。

详细过程:

        

(来源于代码随想录)

如果等并且当前数字大于0 ,就说明他没有意义,我们就到下次循环。

然后total变量储存当前三个数的和,判断total的大小,如果大于0,那就说明右边的数字太大,要往中间移动一下,所以right-=1。如果total<0,那就是左边指针太小,需要往中间移动,所以left+=1。然后继续对当前的两个数字继续进行去重操作。如果当前都是满足题目要求且其余两个数字没有重复,那我们才继续将left指针和right指针向中间移动。

最后当循环退出之后,我们返回结果数组。

leetcode18四数之和

链接:18. 四数之和 - 力扣(LeetCode)

代码:

def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        #对当前数组进行排序
        nums.sort()
        #创建结果集储存结果 实际上是一个二维数组
        result = []

        #对nums进行遍历 并且去重
        for i in range(len(nums)):
            #对第一个数字进行去重
            if i > 0 and nums[i]==nums[i-1]:
                continue
            for k in range(i+1,len(nums)):
                if k>i+1 and nums[k]==nums[k-1]:
                    continue
                left = k+1
                right = len(nums)-1 
                #这里不取等 取等无意义
                while left<right:
                    total = nums[i] + nums[k] + nums[left] + nums[right]
                    #判断是否等于/大于/小于target
                    if total > target:
                        right-=1 
                    elif total <target:
                        left +=1 
                    else:
                        #已经等于target
                        #加入答案数组
                        result.append([nums[i],nums[k],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

这里需要注意一点,与我们的三数之和不一样的是,这里是给定的一个target。并不是一个确定的数字。在三数之和的基础上,是返回三个相加只能=0的三个元素,所以我们判断对排序后的原数组如果第一个数字大于0 我们就可以直接break。

但是在这道题上面,比如说[-4,-1,0,0 ]已经排序好了的数组,target=-5.如果按照三数之和的思路来那么第一个数>target,我们就舍弃了,但是这是一个正确的结果集。所以我们不可以直接判断第一个数字和target大小,我们需要在元组的第一个数字设立一个下标i,然后k = i+1,把这两个元素当作整体,然后设置left = k+1,right = len(nums)-1也就是最后一个数字。判断前面两个元素的整体和 + nums[left] + nums[right]是大于还是小于目标值

如果大于,那就说明我们当前的最后一个元素需要往前移动一位,因为经过排序之后,最后一个元素就是最大的,所以往前移动一位 让这个值变小一点,所以right-=1

如果小于,就说明值小了,left往后移动一位,left+=1 

然后继续对当前的left和right指针所指向的元素做去重处理。

最后返回我们的结果数组

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
第二十二天的算法训练营主要涵盖了Leetcode题目中的三道题目,分别是Leetcode 28 "Find the Index of the First Occurrence in a String",Leetcode 977 "有序数组的平方",和Leetcode 209 "长度最小的子数组"。 首先是Leetcode 28题,题目要求在给定的字符串中找到第一个出现的字符的索引。思路是使用双指针来遍历字符串,一个指向字符串的开头,另一个指向字符串的结尾。通过比较两个指针所指向的字符是否相等来判断是否找到了第一个出现的字符。具体实现的代码如下: ```python def findIndex(self, s: str) -> int: left = 0 right = len(s) - 1 while left <= right: if s[left == s[right]: return left left += 1 right -= 1 return -1 ``` 接下来是Leetcode 977题,题目要求对给定的有序数组中的元素进行平方,并按照非递减的顺序返回结果。这里由于数组已经是有序的,所以可以使用双指针的方法来解决问题。一个指针指向数组的开头,另一个指针指向数组的末尾。通过比较两个指针所指向的元素的绝对值的大小来确定哪个元素的平方应该放在结果数组的末尾。具体实现的代码如下: ```python def sortedSquares(self, nums: List[int]) -> List[int]: left = 0 right = len(nums) - 1 ans = [] while left <= right: if abs(nums[left]) >= abs(nums[right]): ans.append(nums[left ** 2) left += 1 else: ans.append(nums[right ** 2) right -= 1 return ans[::-1] ``` 最后是Leetcode 209题,题目要求在给定的数组中找到长度最小的子数组,使得子数组的和大于等于给定的目标值。这里可以使用滑动窗口的方法来解决问题。使用两个指针来表示滑动窗口的左边界和右边界,通过移动指针来调整滑动窗口的大小,使得滑动窗口中的元素的和满足题目要求。具体实现的代码如下: ```python def minSubArrayLen(self, target: int, nums: List[int]) -> int: left = 0 right = 0 ans = float('inf') total = 0 while right < len(nums): total += nums[right] while total >= target: ans = min(ans, right - left + 1) total -= nums[left] left += 1 right += 1 return ans if ans != float('inf') else 0 ``` 以上就是第二十二天的算法训练营的内容。通过这些题目的练习,可以提升对双指针和滑动窗口等算法的理解和应用能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值