LeetCodeCampsDay6
LeetCodeCampsDay6
以及几题目主要利用hash table的“唯一性”思想解决题目
关键词:哈希表;快慢指针;双指针;用set/dict/当成hash表;
242. 有效的字母异位词
https://leetcode.cn/problems/valid-anagram/
给定两个字符串
s
和t
,编写一个函数来判断t
是否是s
的 字母异位词。
示例 1:
1 | 输入: s = "anagram", t = "nagaram" |
示例 2:
1 | 输入: s = "rat", t = "car" |
提示:
1 <= s.length, t.length <= 5 * 104
s
和t
仅包含小写字母
进阶: 如果输入字符串包含 unicode 字符怎么办?你能否调整你的解法来应对这种情况?
思路
- 使用hash table可解决
- 开辟一块26个int型的数组即可,比如对于字符串s,"a"出现一次,则’a’ - ‘a’的下标(应该是0)对应的数据加一;而对于字符串t,就将反着“检查”,比如’n’出现一次,就要将’n’ - 'a’的下标对应的数据减一;
- 最后,判断是否有「非零」数,若存在则s与t不是字母异位词
- 可以通过判断s与t长度提前判断;
如动画所示
代码
ord(.)用于获取字符的ascii码
- 时间复杂度O(n)
- 空间复杂度O(1),指仅用了26个int型(因为length <= 5*10^4)
1 | class Solution: |
代码改进,可以使用zip减少一次遍历次数
1 | class Solution: |
349. 两个数组的交集
https://leetcode.cn/problems/intersection-of-two-arrays/
给定两个数组 nums1
和 nums2
,返回 它们的 交集 。输出结果中的每个元素一定是 唯一 的。我们可以 不考虑输出结果的顺序 。
示例 1:
1 | 输入:nums1 = [1,2,2,1], nums2 = [2,2] |
示例 2:
1 | 输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4] |
提示:
1 <= nums1.length, nums2.length <= 1000
0 <= nums1[i], nums2[i] <= 1000
思路
-
如果哈希值比较少、特别分散、跨度非常大,使用数组就造成空间的极大浪费,此时就要使用另一种结构体set
-
先将nums1转成unordered_set,再将nums2与这unordered_set比较,得到二次筛选后的unordered_set.
-
在python时使用dict字典即可,将nums1的数据添加到字典了(如果已经存在就不用添加了,也是变相地一种set)
如动画所示
代码
python提供了集合set函数,可以直接使用
1 | class Solution: |
手动实现,使用字典dict和列表list实现
1 | class Solution: |
当然也可以使用数组(list)实现,这题目限制范围是0<=num<=1000数据,可以开1001个位置的数据并按242. 有效的字母异位词的思路
赋值再查询
1 | dictSet = [0] * 1001 |
Pytorch版本
1 | import torch |
202. 快乐数
https://leetcode.cn/problems/happy-number/
编写一个算法来判断一个数 n
是不是快乐数。
「快乐数」 定义为:
- 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
- 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
- 如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n
是 快乐数 就返回 true
;不是,则返回 false
。
示例 1:
1 | 输入:n = 19 |
示例 2:
1 | 输入:n = 2 |
提示:
1 <= n <= 231 - 1
思路一
- 题目中说了会 无限循环,那么也就是说求和的过程中,sum会重复出现,这对解题很重要!
- 可以使用Hash Table,如果sum在表中出现了则说明有循环,可以直接退出;否则就一直找,直到sum=1
代码
1 | class Solution: |
相似的思路,如果不在list中就添加进来,一直计算sum直到等于1停止
1 | class Solution: |
思路二快慢指针
- 这题目可以用快慢指针解决,如果出现了"循环"(sum会重复出现),其实就是“链表有环”的问题
- 慢指针每次走一步;快指针每次走两步。即慢指针每次计算sumN(slow),快指针每次计算sumN(sumN(fast))
- 如果slow == fast则说明有环(有重复的sum)返回False
- while跳出条件是sumN(fast)!=1,这和fast.next不为空即可[在有环链表题目中,while fast and fast.next则执行]
代码
1 | class Solution: |
1. 两数之和
https://leetcode.cn/problems/two-sum/
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案,并且你不能使用两次相同的元素。
你可以按任意顺序返回答案。
示例 1:
1 | 输入:nums = [2,7,11,15], target = 9 |
示例 2:
1 | 输入:nums = [3,2,4], target = 6 |
示例 3:
1 | 输入:nums = [3,3], target = 6 |
提示:
2 <= nums.length <= 104
-109 <= nums[i] <= 109
-109 <= target <= 109
- 只会存在一个有效答案
**进阶:**你可以想出一个时间复杂度小于 O(n2)
的算法吗?
思路
- 使用hash map, 本题目可以使用dict,因为它已经假设每种输入只有一个答案
- 记录table[target - nums[i_1]] = i_1,如果target - nums[i_1] == nums[i_2]则说明target == nums[i_1] + nums[i_2]
- 如果nums[i_2]在table中,则找到了一个匹配的返回i_1和i_2
代码
如果使用双重循环的方式,时间复杂度O(N^2),但空间复杂度可以到O(1);所以本质还是空间换时间
- 时间复杂度O(N)
- 空间复杂度O(N)
1 | class Solution: |
思路二双指针
- 可以使用双指针做,但前提是:数组是有序的(从小到大)
- left指针从左向右遍历;right指针从右向左遍历
- 每次计算left和right所指数字的和;并与target判断大小;如果current_sum大了,则right向左移动;小了则left向右移动;如果相等,有点儿的麻烦的是,需要将left和right在原nums的下标进行还原;
- 初次的还原使用nums.index(nums_sorted[left]),但会出现left_index == right_index的情况,因为题目规定不能使用同一个下标,所以需要将right_index进行调整,调整到nums[left_index+1:].index(nums_sorted[right]) + left_index + 1,也就是强行在nums[left_index+1:]里找right数字对应的下标(返回的是nums[left_index+1:]的下标值,即
相对下标
)所以需要再加上left_index+1成为绝对下标
代码
- 时间复杂度O(N)
- 空间复杂度O(N)—因为占用了个空间存放排序后的数据
1 | # method2 双指针 |