代码随想录算法训练营第6天 | 242.有效的字母异位词、349. 两个数组的交集 、202. 快乐数、1. 两数之和

242.有效的字母异位词

题目描述:leetcode|242.有效的字母异位词
文档讲解:代码随想录
视频讲解:学透哈希表,数组使用有技巧!Leetcode:242.有效的字母异位词
​状态:初刷

题目描述

给定两个字符串 st ,编写一个函数来判断 t 是否是 s 的 字母异位词。
示例 1:
输入: s = “anagram”, t = “nagaram”
输出: true
示例 2:
输入: s = “rat”, t = “car”
输出: false
提示:
1 <= s.length, t.length <= 5 * 104
st 仅包含小写字母
进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
在这里插入图片描述

代码实现

什么是有效字母异位词:

字母异位词:是由重新排列源单词的所有字母得到的一个新单词。

有效字母异位词:给定两个字符串,判定这两个字符串,是不是由相同的字母组成,但是字母的位置可以不一样。

方法一:map

注意:双层循环和双循环是不一样的。

def isAnagram(s: str, t: str) -> bool:
    # 方式1 使用map
    from collections import defaultdict

    # 定义两个字典
    dic_s, dic_t = defaultdict(int), defaultdict(int)

    for i in s:
        dic_s[i] += 1

    for i in t:
        dic_t[i] += 1

    return dic_s == dic_t

方法二:数组

def isAnagram(s: str, t: str) -> bool:
    # 使用数组,因为都是小写英文字母,那么我们定义一个维度为26的数组,出现某个字母,就在这个字母索引/位置上+=1
    record = [0]*26
    for i in s:
        index = ord(i) - ord('a')
        record[index] += 1
    for i in t:
        index = ord(i) - ord('a')
        record[index] -= 1

    for i in range(26):
        if record[i] != 0:
            return False

    return True

方法三:Counter

def isAnagram(s: str, t: str) -> bool:
    # 方式3,使用counter
    from collections import Counter
    s_count = Counter(s)
    t_count = Counter(t)
    return s_count == t_count

知识点

哈希表

哈希表定义

  • 根据关键码的值而直接进行访问的数据结构。

  • 哈希表中关键码就是数组的索引下标,通过下标直接访问数组中的元素。

哈希表的用法

  • 一般都是用来 快速判断一个元素是否出现在集合里。

特点

  • 牺牲了空间换取时间。

哈希表的三种数据结构:

  • 数组、set(集合)、map(映射)
    • 范围可控用数组
    • 数值很大就用set
    • 如果k对应的value的话就用map

Defaultdict

  1. 普通字典dict 不能自动创建未定义的键值对。
    是内置类型dict的一个实例。键必须存在才能访问对应的值,否则会抛出keyerror
record = dict()
result = {}
record['a'] = 1

print(record['a'])  # 输出: 1
print(record['b'])  # KeyError: 'b'

需要手动检查和初始化

  1. 使用 defaultdict(list)创建的字典可以自动创建未定义的键值对。
    使用了collections.defaultdict,一个子类化的字典,可以在访问不存在的键时自动创建默认值。
    提供了一个工厂函数(比如list, int, set等),当访问一个不存在的键时,自动调用这个函数生成默认值并插入字典中,
    可以避免keyerror,适合用来分组、聚合等操作
from collections import defaultdict
result = defaultdict(list)
dic_t = defaultdict(int)

result['a'].append(1)
result['b'].append(2)

print(result['a'])  # 输出: [1]
print(result['c'])  # 输出: [],不会报错,因为自动创建了一个空列表
defaultdict(int)     # 默认是 0
defaultdict(set)     # 默认是空集合
defaultdict(str)     # 默认是空字符串

需要自动处理缺失键的情况(例如进行列表追加、计数、分组等)

Counter

collections.CounterPython 标准库中 collections 模块的一个非常实用的类,用于统计可迭代对象中元素的出现次数。它本质上是一个字典子类(dict subclass),其中键是元素,值是该元素出现的次数。

from collections import Counter

fruits = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
counter = Counter(fruits)

print(counter)
# 输出: Counter({'apple': 3, 'banana': 2, 'orange': 1})
  1. .elements()
    返回一个迭代器,按计数展开所有元素(忽略计数为0或负的)
c = Counter(a=3, b=1)
list(c.elements())  # 输出: ['a', 'a', 'a', 'b']
  1. .most_common([n])
    返回最常见的 n 个元素及计数(默认从高到低排序)
c = Counter('abracadabra').most_common(3)
print(c)  # [('a', 5), ('b', 2), ('r', 2)]
  1. .subtract([iterable-or-mapping])
    从另一个可迭代对象或映射中减去计数(可以是负数)
c = Counter(a=4, b=2)
c.subtract({'a': 1, 'b': 3})
print(c)  # Counter({'a': 3, 'b': -1})
  1. 数学运算(支持 +-&| 等)
  • +: 合并两个 Counter,对应项相加(只保留正数)
  • -: 减法,只保留正的结果
  • &: 取交集,取最小计数
  • |: 取并集,取最大计数
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)

print(c1 + c2)  # Counter({'a': 4, 'b': 3})
print(c1 - c2)  # Counter({'a': 2})
print(c1 & c2)  # Counter({'a': 1, 'b': 1})
print(c1 | c2)  # Counter({'a': 3, 'b': 2})
  • Counter 默认不存储计数为 0 或负数的元素。
  • 如果你想清除计数为 0 的项,可以用.subtract() 后加上 .+(即 +Counter()):
c = Counter(a=2, b=-1)
c = +c
print(c)  # Counter({'a': 2})

ord()

  • 用于获取字符的 Unicode 码点(数值)。适合处理字符串、字符编码、加密算法等场景中。
  • 只接收长度为 1的字符(字符串类型)。
  • 返回该字符对应的Unicode编码(整数)。
print(ord('a'))      # 输出: 97
print(ord('A'))      # 输出: 65
print(ord('0'))      # 输出: 48
print(ord('我'))     # 输出: 25105(中文字符的 Unicode)
print(ord('\n'))     # 输出: 10(换行符)

349. 两个数组的交集

题目描述:leetcode|349. 两个数组的交集
文档讲解:代码随想录
视频讲解:学透哈希表,set使用有技巧!Leetcode:349. 两个数组的交集
​状态:初刷

题目描述

给定两个数组 nums1nums2 ,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]
示例 2:
输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[9,4]
解释:[4,9] 也是可通过的
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 1000
在这里插入图片描述

代码实现

输出结果中的每一个元素一定是唯一的,也就是 输出的结果是去重的,同时可以不考虑输出结果的顺序。

但是这道题没有限制数组的大小,因此无法使用数组做哈希表。

方法一:使用字典和列表/集合

def intersection(nums1, nums2):

    # 先构建一个空字典存储出现在第一个数组中的元素及其出现的次数
    table = {}
    for i in nums1:
        table[i] = table.get(i, 0) + 1
    # 因为结果不重复,所以使用一个集合存储结果
    result = set() # result = []
    # 遍历第二个数组
    for i in nums2:
        if i in table:
            result.add(i) # result.append(i)
            del table[i]

    return list(result)

方法二:使用数组

def intersection(nums1, nums2):
    # 方法二,使用数组,最后将两个结果集进行相乘,如果大于0 则添加进去
    result = []
    # 使用数组
    nums_1 = [0] * 1001
    nums_2 = [0] * 1001
    for num1 in nums1:
        nums_1[num1] += 1
    for num2 in nums2:
        nums_2[num2] += 1
    for i in range(1001):
        if nums_1[i] * nums_2[i] > 0:
            result.append(i)
    return result

方式三:只使用集合

def intersection(nums1, nums2):
    # 方式三:只使用集合
    set_nums1 = set(nums1)
    set_nums2 = set(nums2)

    return list(set_nums1 & set_nums2)

知识点

1. 什么时候用数组,什么时候用map

数组:使用数组来做哈希的题目,是因为题目都限制了数值的大小。

  • 如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费。

set:不仅占用空间比数组大,而且速度慢,set把数值映射到Key上都要做hash计算。对于数据量大的情况,差距比较明显。

2. set集合的相关运算方式

  • 添加
a = set()
a.add([1,2])
#只能是数字、字符串、元组或布尔类型,不能添加可变的数据.
  • 删除
a = {1,2,3}
a.remove(1)
# 要确保删除的元素包含在集合中。
a = {1,2,3}
a.discard()
# 即使删除的元素不在集合中也不会报错。
  • 交集
set1 & set2
  • 并集
set1|set2
  • 差集
set1-set2
  • 对称差集
set1^set2

202. 快乐数

题目描述:leetcode|202. 快乐数
文档讲解:代码随想录
​状态:有点费劲

题目描述

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1
  • 如果这个过程 结果为 1,那么这个数就是快乐数。
  • 如果 n 是 快乐数 就返回 true ;不是,则返回 false

示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1

示例 2:
输入:n = 2
输出:false

提示:
1 <= n <= 231 - 1
在这里插入图片描述

代码实现

如果得到的数据和曾经出现过,那么说明会陷入死循环,因此把每次得到的新的结果存到一个集合中,每次计算得到新的值时都与原有的集合进行比较。

  • 如果新的数据和曾经在原数据和集合中出现过,那么必然会陷入死循环
  • 如果新的数据和为1那么是快乐数
def getsum(n):
    return sum(int(i)**2 for i in str(n))


def isHappy(n: int) -> bool:
    seen = []
    while n != 1:
        if n in seen:
            return False
        seen.append(n)
        n = getsum(n)
def getsum(n):
    num_sum = 0
    while n:
        n,r = divmod(n,10)
        num_sum += r**2
    return num_sum


def isHappy(n: int) -> bool:
    result = set()
    while n not in result:
        result.add(n)
        numsum = getsum(n)
        if numsum == 1:
            return True
        n = numsum
    return False

知识点

给定一个整数 求 这个数 每个位置上的数字的平方和

方法一:使用sum

def getsum(n):
    return sum(int(i)**2 for i in str(n))

方法二:遍历元素

def getsum(n):
    num_sum = 0
    for i in str(n):
        num_sum += int(i)**2
    return num_sum

方法三:使用divmod

def getsum(n):
    num_sum = 0
    while n:
        n,r = divmod(n,10)
        num_sum += r**2
    return num_sum

divmod() Python 的内置函数,用于同时返回除法和取余的结果。

它接受两个参数,表示被除数和除数,返回一个包含两个值的元组,第一个值表示相除的商,第二个值表示相除的余数
num1 = 10
num2 = 3
result = divmod(num1, num2)
print(result) # 输出: (3, 1)

1. 两数之和

题目描述:leetcode|1. 两数之和
文档讲解:代码随想录
视频讲解:梦开始的地方,Leetcode:1.两数之和,学透哈希表,map使用有技巧!
​状态:n刷

题目描述

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。

你可以按任意顺序返回答案。

示例 1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

示例 2:
输入:nums = [3,2,4], target = 6
输出:[1,2]

示例 3:
输入:nums = [3,3], target = 6
输出:[0,1]

提示:

  • 2 <= nums.length <= 104
  • -109 <= nums[i] <= 109
  • -109 <= target <= 109
  • 只会存在一个有效答案
    在这里插入图片描述

代码实现

创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x
然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。

def twosum(nums, target):
    n = len(nums)
    other = {}
    if n < 2:
        return []

    for index in range(n):
        diff = target - nums[index]
        if diff in other:
            return [other[diff], index]

        other[nums[index]] = index
    return []
def twosum(nums, target):
    n = len(nums)
    other = {}
    if n < 2:
        return []
        
    for index in range(n):
        diff = target - nums[index]
        if nums[index] in other:
            return [other[nums[index]], index]

        other[diff] = index
    return []

拓展阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值