代码营打卡 Day6

1. 有效的字母异位词

1.1 哈希表法

判断两个字符串是否由同样的字母组成, 考虑用哈希表, 因为字母一共只有26个, 哈希值小且范围可控, 所以考虑用数组, a-z小写字母的ASCII码是连续的

ord()函数是一个python中的内置函数, 用来返回指定字符的Unicode码, 也就是字符在Unicode编码表中的数值表示.

为了避免麻烦, 直接用数组中的字符i的ord()减去ord最开始的a, 得到字符在record中的索引(这里注意遍历的是字母本身而不是索引, 也要注意ord()并非ord[])

用这种方式记录每个字母在字符串中出现的次数, 其中每个索引对应一个字母, 如果出现了一次就加1, 在另一个字符串中出现一次就减1, 最后检查得到的数组元素是否都为0

        record = [0] * 26

        if len(s) != len(t):
            return False  # 如果两字符串长度不同,直接返回False
        for i in s:
            record[ord(i) - ord('a')] += 1
        for i in t:
            record[ord(i) - ord('a')] -= 1
        for i in range(26):
            if record[i] != 0:
                return False
        return True

1.2 counter法

1.2.1 counter类简介

Counter 是 Python 标准库 collections 模块中的一个类,用于对数据中的元素进行计数。它可以接收多种形式的输入,如列表、字符串等,并返回一个字典,其中的键是输入数据中的唯一元素,值是这些元素在输入数据中出现的次数. 例如

from collections import Counter
a_count = Counter(s)
  • s 可以是任何可迭代的数据类型,例如字符串、列表或元组。
  • Counter(s) 会创建一个计数器对象,其中包含了 s 中每个元素的出现次数。
  • a_count 将是一个字典类型的对象,其中包含了从 s 中提取的元素及其对应的计数。

most_common() 还可以返回数据中出现次数最多的元素及其计数。

1.2.2 counter法解题

就是看两个字符串生成的字典是否完全一样

用counter解决这道题的方法如下:

class Solution(object):
    def isAnagram(self, s: str, t: str) -> bool:
        from collections import Counter
        a_count = Counter(s)
        b_count = Counter(t)
        return a_count == b_count

1.3 defaultdict法

1.3.1 defaultdict介绍

defaultdict是创建字典的方法, 是python标准库collection模块中的一种特殊类型的字典, 特点是提供一个默认值, 当字典被访问时, 如果键不存在, 则返回一个默认值而不是抛出“Keyerror”

在 Python 的 collections 模块中使用 defaultdict 时,需要提供一个无参数的函数或类型来作为默认值的工厂。

defaultdict(0)是错误的用法. 括号里面必须是一个可调用的对象. 

在这里,int 是 Python 中的标准整数类型。当作为 defaultdict 的参数时,int 用作默认工厂函数,这意味着当字典在尝试访问一个不存在的键时,会自动调用 int() 来产生一个默认值。由于调用 int() 返回 0,因此当访问一个不存在的键时,defaultdict(int) 会自动为这个键赋值 0

也可以这样写d = defaultdict(lambda: 0), 还有一种查找key时的写法, 比如 my_dict.get('key', 0), 如果字典中找不到key这个键, 就返回0

1.3.2 defaultdict法解题

就是创建两个字典, 只统计出现过的字母的数量, 看两个字符串生成的字典是否完全一样

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        from collections import defaultdict
        
        s_dict = defaultdict(int)
        t_dict = defaultdict(int)
        for x in s:
            s_dict[x] += 1
        
        for x in t:
            t_dict[x] += 1
        return s_dict == t_dict

2. 两个数组的交集(349)

2.1.用字典

用一个字典记录下第一个数组的内容, key是数组里面的数值, value是出现次数, 用get 如果之前没有过这个数值, 则返回0, 之后再加1, 如果之前有过, 那么就直接加1. 这样就可以统计数组中每个数值出现过的次数

然后遍历nums2里面的数, 看能不能作为key出现在字典中, 如果可以如此, 就把这个数值添加到res中, res就是重复出现过的数

从字典中删除已经处理过的项可以减少未来查找或操作的成本。尤其是当 table 很大时,删除不再需要的键可以帮助降低内存占用和可能的查找时间。我们只需要处理table和num2相匹配的第一个相应的数字, 防止再次匹配同一个数字

        table = {}
        res = set()
        for i in nums1:
            table[i] = table.get(i, 0) + 1
        for i in nums2:
            if i in table:
                res.add(i)

                del table[num]

        return list(res)

2.2 用数组

这里要注意的主要是count中是用索引来记录num中的值的, num中的值由num的长度决定, 而count的值对应的就是数字出现的次数

另外要注意的是, 判断有交集的条件是出现次数的成绩大于 0

        count1 = [0]*1001
        count2 = [0]*1001
        res = []

        for i in range(len(nums1)):
            count1[nums1[i]] += 1

        for i in range(len(nums2)):
            count2[nums2[i]] += 1

        for i in range(1001):
            if count1[i] * count2[i] != 0:
                res.append(i)
        return res

2.3 用集合

直接用set取交集

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        return list(set(nums1) & set(nums2))

3. 快乐数(202)

「快乐数」定义为:对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和,然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。如果 可以变为  1,那么这个数就是快乐数。

3.1 求各个位数平方和的方法

3.1.1 数学计算

python中有divmod函数

 n, r = divmod(n, 10) 

这行代码的意思是把n除以10的商赋予给n, 将余数赋予给r

也就是说如果n=123, n更新为12, r更新为3, 第二次循环中n更新为1, 这样计算r的平方和也就是计算每一位的平方和

类似的写法有

        while n:
            new_sum += (n%10) ** 2
            n = n//10

3.1.2 把数字转化为字符串

           new_num = 0
           n_str = str(n)
           for i in n_str:
               new_num+=int(i)**2

3.2 判断是否重复出现的方法

题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!

当我们遇到了要快速判断一个元素是否出现集合里的时候,就要考虑哈希法了。

3.2.1 集合法

class Solution(object):
    def isHappy(self, n):
        """
        :type n: int
        :rtype: bool
        """
        record = set()

        while True:
            n = self.get_sum(n)
            if n==1:
                return True
            
            if n in record:
                return False
            else:
                record.add(n)

    def get_sum(self, n):
        new_sum = 0
        while n:
            n, r = divmod(n, 10) 
            new_sum += r ** 2
        return new_sum

3.2.2. 数组法

数组法其实就是用数组记录是否会循环(重复), 和集合法差别不大

       record = []
       while n not in record:
           record.append(n)

3.2.3 双指针法

因为如果不是快乐数, 就会出现循环, 所以用fast和slow两个指针跟踪sum的更新情况, fast一次算两个sum, slow每次算一个sum, 如果二者相等, 则说明出现循环(因为fast和slow速度相差1, 所以如果有循环一定会相等)

举例 4:  4, 16, 37, 58, 89, 145, 42, 20, 4

fast: 37, 89, 42, 4, 37, 89, 37, 89, 42, 4, 37

slow:4, 16, 37, 58, 89, 145, 42, 20, 4, 16, 37

        

   def isHappy(self, n: int) -> bool:        
       slow = n
       fast = n
       while self.get_sum(fast) != 1 and self.get_sum(self.get_sum(fast)):
           slow = self.get_sum(slow)
           fast = self.get_sum(self.get_sum(fast))
           if slow == fast:
               return False
       return True

4. 两数之和

这道题的核心其实是想到找到另一个符合条件的数是否被遍历过, 如target=9, 遍历到的是6, 就找3有没有之前被遍历过, 如果有就返回下标

注意两和问题只需要找出其中任意两个其和为target就可以

4.1 字典法

        record = {}
        index = 0
        for i in nums:
            if target - i in record:
                return [record[target-i], index]
            else:
                record[i] = index
                index += 1
        return []

其中字典法还可以用一个内置函数简化 for index, value in enumerate(nums):, 这行代码用来遍历列表或者其他可迭代对象, 同时获取每个元素的索引和值

  • 例如,如果 nums = [10, 20, 30]enumerate(nums) 会生成 (0, 10)(1, 20)(2, 30)

index, value是元组解包的方式, 将元组氛围index索引和value对应元素值这两部分

找不到target-value, 就把这个写入字典中即可

        for index, value in enumerate(nums):  
            if target - value in records:   # 遍历当前元素,并在map中寻找是否有匹配的key
                return [records[target- value], index]
            records[value] = index    # 如果没找到匹配对,就把访问过的元素和下标加入到map中
        return []

4.2 集合法

其实就是用集合存入元素, 然后如果集合中有需要的元素, 就用nums.index()返回在数组中的索引值, 注意nums.index()如果是数组中不存在元素, 会丢出ValueError的异常 

    def twoSum(self, nums: List[int], target: int) -> List[int]:
        #创建一个集合来存储我们目前看到的数字
        seen = set()             
        for i, num in enumerate(nums):
            complement = target - num
            if complement in seen:
                return [nums.index(complement), i]
            seen.add(num)

4.3 暴力法

两个for循环, 挨个相加对比, 复杂度应该是O(n**2)

    def twoSum(self, nums: List[int], target: int) -> List[int]:
        for i in range(len(nums)):
            for j in range(i+1, len(nums)):
                if nums[i] + nums[j] == target:
                    return [i,j]

4.4 双指针法

首先用sorted(nums)对数组进行排序, 再将两个指针left和right分别放在数组最左边和最右边

直到两个指针相遇之前都一直循环, 在循环内部计算left和right指向元素的和, 记为current_sum

如果cur_sum等于target, 就找到两个元素在原始数组nums中的索引, 这里要考虑一个特殊情况, 就是两个元素相等时, 用index会返回这个元素第一次出现的位置的索引

所以要找第二次出现位置的索引, 从索引第一次出现的位置+1到数组末尾的部分, 就跳过课第1次找到的索引, 但是注意这里找到的索引是切割以后第一次出现位置下一个数作为起点得到的索引, 为了还原成在原数组的索引, 要加上第一次出现位置的索引和1

if left_index == right_index:
    right_index = nums[left_index+1:].index(nums_sorted[right]) + left_index + 1

如果cur_sum小于target就把left向右移动, 增加和的值

如果cur_sum大于target就把right向左移动, 减少和的值

    def twoSum(self, nums: List[int], target: int) -> List[int]:
        # 对输入列表进行排序
        nums_sorted = sorted(nums)
        
        # 使用双指针
        left = 0
        right = len(nums_sorted) - 1
        while left < right:
            current_sum = nums_sorted[left] + nums_sorted[right]
            if current_sum == target:
                # 如果和等于目标数,则返回两个数的下标
                left_index = nums.index(nums_sorted[left])
                right_index = nums.index(nums_sorted[right])
                if left_index == right_index:
                    right_index = nums[left_index+1:].index(nums_sorted[right]) + left_index + 1
                return [left_index, right_index]
            elif current_sum < target:
                # 如果总和小于目标,则将左侧指针向右移动
                left += 1
            else:
                # 如果总和大于目标值,则将右指针向左移动
                right -= 1

  • 35
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值