代码营打卡 Day7

1. 四数之和(454)

这道题考查四个数组中, 有几组组合可以组成和为0. 考虑把四个数组划分为两个, 两两一组, 如果划分为一三的话, 复杂度就是O(n**3)了, 所以不推荐

然后就是把a+b的结果存到字典中, key是a+b的数值, value是a+b出现的次数, 然后再遍历c+d, 看是否有需要的a+b值(即-c-d的值)已经出现在字典中. 如果有的话, count加上value值(这里注意是加value值而不是1), 因为要计算一共有多少组组合

        res = dict()
        n = len(nums1)
        for i in range(n):
            for j in range(n):
                key = nums1[i] + nums2[j]
                if key not in res:
                    res[key] = 0
                res[key] += 1

        result = 0
        for a in range(n):
            for b in range(n):
                key1 = -nums3[a] - nums4[b]
                result += res.get(key1, 0)
        return result

这里稍微注意一下这一行

        if key not in res:
           res[key] = 0
        res[key] += 1

这里的res[key]是无条件为key的值➕1, 所以初始化的值适合设置为0. 之前把res[key]初始化为1就出错了, 可以改为:

        if key not in res:
            res[key] = 1  # key第一次出现,计数为1
        else:
            res[key] += 1 

还可以用defaultdict:

from collections import defaultdict

res = defaultdict(int)  # 默认值为0

for i in range(n):
    for j in range(n):
        key = nums1[i] + nums2[j]
        res[key] += 1  

defaultdict还有一种写法

        rec = defaultdict(lambda : 0)
        for i in nums1:
            for j in nums2:
                rec[i+j] += 1

或者用get函数:

        hashmap = dict()
        for n1 in nums1:
            for n2 in nums2:
                hashmap[n1+n2] = hashmap.get(n1+n2, 0) + 1

最后提一下, 这道题我的解法并不好, 可以直接遍历num中的数值, 我是基于每个数组长度都是n才能写出的, 不好

2. 赎金信(383)

就是说信中有字符, magazine中有字符, 判断前者的字符能不能由后者组成, 即后者是否包含前者

        list1 = [0]*26
        list2 = [0]*26
        for i in ransomNote:
            list1[ord(i) - ord("a")] += 1
        for j in magazine:
            list2[ord(j) - ord("a")] += 1
        for i in range(26):
            if not list1[i] <= list2[i]:
                return False
        return True

这题用数组不难 , 但是要注意一点, 就是写的时候我也是考虑怎么写对于所有的list1中的对应值要小于等于list2中的, 答案是如果不小于就return false就行

就是如何判断1有的2一定有还有其他方法, 比如在2的数组中, 1的就减1, 如果出现小于0则说明ransoNote中出现的字符, magazine中没有

还可以用count, 小的减去大的, counter减法中, 如果计数结果为0或者负数, 不会出现在count中, 如果结果为空会返回一个false, return的就是true, 如果不能完全覆盖最后返回false

from collections import Counter

class Solution:
    def canConstruct(self, ransomNote: str, magazine: str) -> bool:
        return not Counter(ransomNote) - Counter(magazine)

或者是, 对于ransomnote中的每个唯一字符c, 计算字符c在ransomnote和magazine中的出现次数, 检查是否magazine中的次数是否都是不少于ransomnote中的次数

        return all(ransomNote.count(c) <= magazine.count(c) for c in set(ransomNote))

3. 三数之和(15)

三数之和问题就是要看一个数组中是否存在三个数和为0, 三个数的值可以重复, 但是一个数不能用两次, 并且同一个组合只需要记录一次

用双指针法解决这个问题, 首先先将数组排序, 确定i, 遍历整个数组, 这里要注意一点就是i如果和前一个数字相同就跳过这个数. 那么到底是nums[i] == nums[i+1] 还是nums[i] == nums[i-1]

答案是后者, 因为不要忘了left是i的下一个数, 而i和left同样取值是允许的. 如果出现这种情况, 就continue, 跳过后面的步骤, 继续执行for循环, 改变i的值, 直到和前面一个不相等

设定两个指针, 一个是left, 一个是right, left从i后面一个数开始, right从最后一个数开始

也就是 left = i+1, right = len(num) - 1

紧接着考虑循环条件是right >= left还是right > left, 因为不能出现一个数使用两次的情况, 所以right和left不能取等, 所以是选择后者

然后就是记录三个指针指向数的和, 如果大于0, right向左移动, 如果小于0, 则left向右移动

找到等于0 的情况就添加入result中

找到一个有效三元组后执行内层的while, 跳过所有与当前num[right]以及nun[left]相同的元素, 防止下次迭代中再使用相同的元素

    def threeSum(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        """
        result = []
        nums.sort()

        for i in range(len(nums)):
            if nums[i] > 0:
                return result

            if i>0 and nums[i] == nums[i-1]:
                continue
            
            left = i+1
            right = len(nums) - 1

            while right>left:
                sum1 = nums[i] + nums[left] + nums[right]

                if sum1 < 0 :
                    left += 1
                elif sum1 > 0:
                    right -= 1
                else:
                    result.append([nums[i], nums[left], nums[right]])

                    while right > left and nums[right] == nums[right - 1]:
                        right -= 1
                    while right > left and nums[left] == nums[left + 1]:
                        left += 1
                    
                    right -= 1
                    left += 1
            
        return result

 4. 四数之和(18)

4.1 双指针

四数之和就是在三数的基础上再加上一个循环, 最后的复杂度是O(n**3)

这道题的重点在于剪枝和去重, 注意不能用num[k] > target的方式来剪枝, 这是因为虽然k是最小的元素, 但是后面的也有可能是负数, 这样相加可能缩小值, 从而得到target

要剪枝的话, 要用if nums[i] > target and nums[i] > 0 and target > 0:

去重要用 if i > 0 and nums[i] == nums[i-1]:

后来剪枝将nums[k] + nums[i]看作一个整体

class Solution:
    def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
        nums.sort()
        n = len(nums)
        result = []
        for i in range(n):
            if nums[i] > target and nums[i] > 0 and target > 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[right] == nums[right-1]:
                            right -= 1
                        left += 1
                        right -= 1
                    elif s < target:
                        left += 1
                    else:
                        right -= 1
        return result

4.2 字典 

首先建立一个字典freq, 用来记录数组nums中每个数字出现的次数

freq = {}
for num in nums:
    freq[num] = freq.get(num, 0) + 1

接着用一个集合set来存储答案, 用三重循环遍历数组nums中每一个可能的三元组合, 并且i<j<k保证组合的唯一性

接着看需要的第四个数val是否在字典freq中, 如果在那么判断是否能用

即nums i,j,k使用的val的数量是否小于字典中记录的数量, 如果的确小于说明这个字典中存放的val是可以用的, 将这个四元组加入答案中

用tuple(sorted([nums[i], nums[j], nums[k], val]))确保四元组是有序的, 从而避免重复,

而此时仍然是一个列表, 没有办法存入set中去重, 所以要先转化为元组即用tuple(sorted([nums[i], nums[j], nums[k], val])), 然后再存入set中, 因为排序了又在set中去重, 得到的就是符合题意的元组

例如,四元组 (1, 3, 2, 4)(1, 2, 3, 4) 在排序后都会变为 (1, 2, 3, 4)

ans = set()
for i in range(len(nums)):
    for j in range(i + 1, len(nums)):
        for k in range(j + 1, len(nums)):
            val = target - (nums[i] + nums[j] + nums[k])
            if val in freq:
                count = (nums[i] == val) + (nums[j] == val) + (nums[k] == val)
                if freq[val] > count:
                    ans.add(tuple(sorted([nums[i], nums[j], nums[k], val])))

所以最后要从元组转化为列表 

return [list(x) for x in ans]

  • 7
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Uniapp 是一款基于 Vue.js 的跨平台开发框架,可以用它来开发多个平台的应用程序,包括 iOS、Android、Web、微信小程序、支付宝小程序等等。实现区域打卡代码,可以借助定位 API 实现,步骤如下: 1. 在 manifest.json 文件中添加定位权限: ``` "app-plus": { "permissions": { "location": { "desc": "需要获取您的地理位置权限才能打卡", "scopes": "scope.userLocation" } } } ``` 2. 在页面中调用定位 API 获取当前位置: ``` uni.getLocation({ type: 'gcj02', // 坐标系类型 success: function(res) { // res.latitude:纬度,浮点数,范围为-90~90 // res.longitude:经度,浮点数,范围为-180~180。 // res.speed:速度,浮点数,单位m/s // res.accuracy:位置精度 }, fail: function(res) { uni.showToast({ title: '获取位置失败', icon: 'none' }); } }); ``` 3. 获取到当前位置后,判断是否在指定的区域内: ``` // 示例代码,需要根据实际需求修改 function isInArea(latitude, longitude) { var area = [ { lat: 31.2637, lng: 121.5387 }, // 上海市浦东新区 { lat: 31.2375, lng: 121.4816 }, // 上海市徐汇区 { lat: 31.2183, lng: 121.4529 } // 上海市长宁区 ]; var polygon = new AMap.Polygon({ path: area, strokeColor: "#FF33FF", strokeWeight: 6, strokeOpacity: 0.2, fillOpacity: 0.4, fillColor: '#1791fc', }); return polygon.contains(new AMap.LngLat(longitude, latitude)); } ``` 4. 根据上面的判断结果,执行打卡操作: ``` if (isInArea(res.latitude, res.longitude)) { // 在指定区域内,执行打卡操作 } else { // 不在指定区域内,提示用户 uni.showToast({ title: '当前不在打卡范围内', icon: 'none' }); } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值