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赎金信
思路:首先这道题一个暴力的解决思路就是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三数之和
首先明确一点,这里的重复元组并不是代表元素不能重复!例如(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四数之和
代码:
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指针所指向的元素做去重处理。
最后返回我们的结果数组