代码训练营 Day7 | 哈希表02

今日第一题:

​​​​​​454. 4Sum II

Given four integer arrays nums1nums2nums3, and nums4 all of length n, return the number of tuples (i, j, k, l) such that:

  • 0 <= i, j, k, l < n
  • nums1[i] + nums2[j] + nums3[k] + nums4[l] == 0

Example 1:

Input: nums1 = [1,2], nums2 = [-2,-1], nums3 = [-1,2], nums4 = [0,2]
Output: 2
Explanation:
The two tuples are:
1. (0, 0, 0, 1) -> nums1[0] + nums2[0] + nums3[0] + nums4[1] = 1 + (-2) + (-1) + 2 = 0
2. (1, 1, 0, 0) -> nums1[1] + nums2[1] + nums3[0] + nums4[0] = 2 + (-1) + (-1) + 0 = 0

Example 2:

Input: nums1 = [0], nums2 = [0], nums3 = [0], nums4 = [0]
Output: 1

不完整的代码如下:

### 重点是1、可以有重复的数字
###      2、可以两个两个算,map{key:ab的和数,value:cd的和数}

nums1 = [1,2]
nums2 = [-2,-1]
nums3 = [-1,2]
nums4 = [0,2]

unordered_map = {} #定义一个字典存ab和cd的两数之和

for i in nums1:
    for j in nums2:
        unordered_map[i+j] = 0 #好像这里必须要有初始化一下为0

print(unordered_map) 

#但是这样的话,好像会减去重复的值例如 1 -1 和 2 -2都是0了
#✨解决方法:可以在这里做一个判断,如果i+j出现过,就value+1
# 然后在最后一步统计的时候,把这个漏掉的值加上,也就是count不加1而是加value

count = 0

# 在遍历一下cd
for k in nums3:
    for n in nums4:
        if (0-(k+n)) in unordered_map:
            count += 1

解题步骤:

  1. 首先定义 一个unordered_map,key放a和b两数之和,value 放a和b两数之和出现的次数
  2. 遍历大A和大B数组,统计两个数组元素之和,和出现的次数,放到map中。
  3. 定义int变量count,用来统计 a+b+c+d = 0 出现的次数。
  4. 在遍历大C和大D数组,找到如果 0-(c+d) 在map中出现过的话,就用count把map中key对应的value也就是出现次数统计出来。
  5. 最后返回统计值 count 就可以了

今日第二题:

383. Ransom Note

Given two strings ransomNote and magazine, return true if ransomNote can be constructed by using the letters from magazine and false otherwise.

Each letter in magazine can only be used once in ransomNote.

Example 1:

Input: ransomNote = "a", magazine = "b"
Output: false

Example 2:

Input: ransomNote = "aa", magazine = "ab"
Output: false

Example 3:

Input: ransomNote = "aa", magazine = "aab"
Output: true
## 赎金信问题
## magazine 集合更大 ransom note 集合更小
## magazine ---> 构成 ransom note
## 注意⚠️每个字符只能使用一次!

ransomNote = "a"
magazine = "b"

mag_map = {} ## 注意⚠️这里用数组更好,不用map,用map查询时间更大

## magazine应该需要在map里
## 然后循环ransom note里的字符
## 如果都能在map里找到,则可以True,如果不能,则False

### 自己的解法
###1、把magazine字符串里分解成为map的key
for char in magazine:
    mag_map[char] += 1

print(mag_map)

###2、循环ransomnote字符串,看看是否能在magmap里找到
flag = True

for char in ransomNote:
    if char in mag_map and mag_map[char].value() > 0:
        mag_map[char] -= 1
    else:
        flag = False
        break

###3、结果
print(flag)

自己的解法失败了, 因为没有考虑到magazine只能扣除一次字母,扣完一次字母之后就没有其他字母可以用了。

下面是看了答案之后写的

### 看答案的用数组的解法 要用c-'a' 或者 ord(c)-ord('a')

"""
# ord()函数用于获取字符的Unicode代码点(整数表示)
char = 'A'
unicode_value = ord(char)
print(unicode_value)  
# This will print 65, which is the Unicode code point for 'A'

"""

## 前置check
if len(ransomNote) > len(magazine):
    print(False) 

## 定义一个数组
record = [0]*26

## 遍历两个数组,有的话+1,没有的话-1
for char in magazine:
    record[ord(char) - ord('a')] += 1
    
for char in ransomNote:
    record[ord(char) - ord('a')] -= 1

## 如果数组中存在负数,说明ransomNote字符串总存在magazine中没有的字符
for i in record:
    if i < 0:
        print False

今日第三题:

15. 3Sum

Given an integer array nums, return all the triplets [nums[i], nums[j], nums[k]] such that i != ji != k, and j != k, and nums[i] + nums[j] + nums[k] == 0.

Notice that the solution set must not contain duplicate triplets.

Example 1:

Input: nums = [-1,0,1,2,-1,-4]
Output: [[-1,-1,2],[-1,0,1]]
Explanation: 
nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0.
nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0.
nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0.
The distinct triplets are [-1,0,1] and [-1,-1,2].
Notice that the order of the output and the order of the triplets does not matter.

Example 2:

Input: nums = [0,1,1]
Output: []
Explanation: The only possible triplet does not sum up to 0.

Example 3:

Input: nums = [0,0,0]
Output: [[0,0,0]]
Explanation: The only possible triplet sums up to 0.
### 1、排序
result = []
#nums = [-1,0,1,2,-1,-4]
sorted_nums = sorted(nums)

### 2、判断最小的数是否就大于0了
if sorted_nums[0] > 0:
    print(result)

### 3、滑动窗口法解决



for i in range(len(sorted_nums)):
    if (sorted_nums[i] > 0):
        return result #第一个数是否大于0
    
    if ( i>0 and sorted_nums[i] == sorted_nums[i-1]):
        continue #去重
    
    left = i + 1
    right = len(sorted_nums)-1 #记得写在里面才会更新
    
    while left < right:
        if sorted_nums[i]+sorted_nums[left]+sorted_nums[right]==0: #记录答案组
            #这里result数组也不会添加
            #result.append(sorted_nums[i],sorted_nums[left],sorted_nums[right])
            result.append([sorted_nums[i],sorted_nums[left],sorted_nums[right]])
            
            # 跳过相同的元素以避免重复,这一步忘了,还有这个判断去重是right和left分别
            while right > left and sorted_nums[right] == sorted_nums[right - 1]:
                right -= 1
            while right > left and sorted_nums[left] == sorted_nums[left + 1]:
                left += 1
            
            left += 1
            right -= 1 
            
        elif sorted_nums[i]+sorted_nums[left]+sorted_nums[right]>0:
            right -= 1
        else:
            left += 1

return result

今日第四题:

18. 4Sum

Given an array nums of n integers, return an array of all the unique quadruplets [nums[a], nums[b], nums[c], nums[d]] such that:

  • 0 <= a, b, c, d < n
  • abc, and d are distinct.
  • nums[a] + nums[b] + nums[c] + nums[d] == target

You may return the answer in any order.

Example 1:

Input: nums = [1,0,-1,0,-2,2], target = 0
Output: [[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]

Example 2:

Input: nums = [2,2,2,2,2], target = 8
Output: [[2,2,2,2]]s

首先与四数相加:

给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0。

为了使问题简单化,所有的 A, B, C, D 具有相同的长度 N,且 0 ≤ N ≤ 500 。所有整数的范围在 -2^28 到 2^28 - 1 之间,最终结果不会超过 2^31 - 1 。

不同点在于:

1、4sum2 target = 0;而4sumtarget不定,这样不能单纯从>0<0来判断

2、4sum2 已经给四个数组nums1234,而4sum只是在一个数组里转nums

nums = [1,0,-1,0,-2,2]
target = 0

"""
    还是不会,只能看答案写
    在三数之和基础上外套一个小循环for
    [][][][][][]
    k i left  right
    
    重点⚠️1、剪枝
    nums[i]>0 <===>  nums[i]>target ? 
    x
    没考虑到负数的情况
    加一个判断〉0
    2、去重
    答案给的去重有k > 0|i > k + 1这两个条件?为啥?
    跟三数之和一样,因为是[i]=[i-1],这个条件一定要在i>0时才能生效,因为i=0的时候i-1是-1没有这个东西
    
"""

nums.sort()
result = []
n = len(nums)
for i in range(n):
    if nums[i] > target and nums[i] > 0: #剪枝
        break
    if i > 0 and nums[i] == nums[i-1]: #去重
        continue
    for j in range(i+1,n):
        if nums[i] + nums[j] > target and target > 0:
            break
        if j > i + 1 and nums[j] == nums[j-1]:
            continue
        left, right = j+1, n-1
        while left < right:
            s = nums[i] + nums[j] + nums[left] + nums[right]
            if s == target:
                result.append(nums[i], nums[j], nums[left], nums[right])
                while left < right and nums[left] == nums[left+1]:
                    left += 1
                while left < right and nums[left] == nums[left+1]:
                    right -= 1
                left += 1
                right -= 1
            elif s < target:
                left += 1
            else:
                right -= 1
return result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值