Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)

查找表

  • 查找表
    • 第一类: 查找有无--set
    • 第二类: 查找对应关系(键值对应)--dict
    • 第三类: 改变映射关系--map
  • 查找表算法应用
    • 349. 两个数组的交集
    • 350. 两个数组的交集 II
    • 202. 快乐数
    • 290. 单词规律
    • 205. 同构字符串
    • 451. 根据字符出现频率排序
    • 242. 有效的字母异位词
  • 二分查找
    • 35. 搜索插入位置
    • 540. 有序数组中的单一元素
    • 410. 分割数组的最大值

查找表

第一类: 查找有无–set

元素’a’是否存在,通常用set:集合
set只存储键,而不需要对应其相应的值。
set中的键不允许重复

第二类: 查找对应关系(键值对应)–dict

元素’a’出现了几次:dict–>字典
dict中的键不允许重复

第三类: 改变映射关系–map

通过将原有序列的关系映射统一表示为其他

参考资料:
https://github.com/datawhalechina/team-learning-program/blob/master/LeetCodeClassification/3.%E6%9F%A5%E6%89%BE.md

查找表算法应用

349. 两个数组的交集

349. 两个数组的交集(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第1张图片
输出结果中的每个元素唯一,即不需要考虑元素出现的次数,用set即可
Python:

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        if not nums1 or not nums2:
            return []
        
        set1 = set(nums1)
        set2 = set(nums2)

        return set1&set2

复杂度分析:
时间复杂度:平均情况O(M+N),最坏情况下O(M*N),内置函数
空间复杂度:O(M+N),最坏情况下,元素都不相同

C++:

class Solution {
     
public:
    vector<int> intersection(vector<int>& nums1, vector<int>& nums2) {
     
   
        unordered_set<int> set;
        unordered_set<int> set1(nums1.begin(),nums1.end());
        for(int num:nums2){
     
            if(set1.count(num)==1) set.insert(num);
        }
        return vector<int>(set.begin(),set.end());
    }
};

350. 两个数组的交集 II

350. 两个数组的交集 II(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第2张图片
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第3张图片
与349的区别,输出结果中包含元素出现的次数,考虑dict
方法一:

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        if not nums1 or not nums2:
            return []
        
        dic1 = {
     }
        for num in nums1:
            if num in dic1:
                dic1[num] += 1
            else:
                dic1[num] = 1
        
        res = []
        for num in nums2:
            if num in dic1:
                if dic1[num]>0:
                    res.append(num)
                    dic1[num] -= 1
        
        return res

用collection模块

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:
        from collections import Counter
        if not nums1 or not nums2:
            return []
        
        dic1 = Counter(nums1)
        
        res = []
        for num in nums2:
            if num in dic1:
                if dic1[num]>0:
                    res.append(num)
                    dic1[num] -= 1
        
        return res

方法二:
对应进阶的第一问,如果已排序,则采用双指针

class Solution:
    def intersect(self, nums1: List[int], nums2: List[int]) -> List[int]:

        if not nums1 or not nums2:
            return []
        
        nums1.sort()
        nums2.sort()

        p1 = 0
        p2 = 0
        res = []
        
        while p1<len(nums1) and p2<len(nums2):
            if nums1[p1]==nums2[p2]:
                res.append(nums1[p1])
                p1 += 1
                p2 += 1
            elif nums1[p1]<nums2[p2]:
                p1 += 1
            else:
                p2 += 1

        return res

复杂度分析:
时间复杂度:O(mlogm+nlogn),其中 m 和 n 分别是两个数组的长度。对两个数组进行排序的时间复杂度是 O(mlogm+nlogn),遍历两个数组的时间复杂度是 O(m+n),因此总时间复杂度是O(mlogm+nlogn)
空间复杂度:除了res数组,不需要额外的空间。

进阶

  1. 如果给定的数组已经排好序呢?你将如何优化你的算法?
    方法二,双指针
  2. 如果 nums1 的大小比 nums2 小很多,哪种方法更优?
    方法一,nums2只需要遍历一遍即可
  3. 如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
    方法一,每次读取nums2的一部分数据

202. 快乐数

202. 快乐数(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第4张图片
如果计算得到的数在之前曾经出现过,就会进入无限循环,因此用set。

class Solution:
    def isHappy(self, n: int) -> bool:
        
        def get_next(n):
            res = 0
            while n>0:               
                n1 = n%10
                n = n//10
                res += n1*n1
            return res
        
        set1 = set()
        while n!=1 and n not in set1:
            set1.add(n)
            n = get_next(n)

        return n==1

290. 单词规律

290. 单词规律(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第5张图片
在这里插入图片描述

class Solution:
    def wordPattern(self, pattern: str, str: str) -> bool:
        str1 = str.split()
        if len(pattern)!=len(str1):
            return False

        l = 0
        dic = {
     } #pattern[l]:str1[l]

        while l<len(pattern):
            if pattern[l] in dic:
                if dic[pattern[l]] != str1[l]:
                    return False
            else:
                if str1[l] in dic.values(): ##如果pattern[l] not in dic, 但str1[l]出现过, 则为False
                    return False
                dic[pattern[l]] = str1[l]
            l += 1

        return True

205. 同构字符串

205. 同构字符串(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第6张图片
同上一题

class Solution:
    def isIsomorphic(self, s: str, t: str) -> bool:
        l = 0
        dic = {
     }

        while l<len(s):
            if s[l] in dic:
                if dic[s[l]] != t[l]:
                    return False
            else:
                if t[l] in dic.values():
                    return False
                dic[s[l]] = t[l]
            l += 1
        return True

451. 根据字符出现频率排序

451. 根据字符出现频率排序(中等)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第7张图片

class Solution:
    def frequencySort(self, s: str) -> str:
        from collections import Counter
        s1 = Counter(s)

        s2 = sorted(s1.items(),key=lambda item:item[1],reverse=True)

        res = ''
        for key,value in s2:
            res += key*value
        return res

Tips:

通过sorted的方法进行value排序,对字典排序后无法直接按照字典进行返回,返回的为列表元组:

#对value值由大到小排序
s = sorted(s_dict.items(), key=lambda item:item[1], reverse = True)

#对key由小到大排序
s = sorted(s_dict.items(), key=lambda item:item[0])

print(s) #[('e', 2), ('t', 1), ('r', 1)]
print(type(s)) #

输出为字符串的情况下,可以由字符串直接进行拼接:

#由key和value相乘进行拼接
's' * 5 + 'd'*2

242. 有效的字母异位词

242. 有效的字母异位词(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第8张图片

class Solution:
    def isAnagram(self, s: str, t: str) -> bool:
        from collections import Counter
        l1 = len(s)
        l2 = len(t)
        if l1!=l2:
            return False
        if l1==0 and l2==0:
            return True
        
        dic = Counter(s)

        for c in t:
            if c not in dic:
                return False
            dic[c] -= 1
        
        for key,value in dic.items():
            if value!=0:
                return False
        return True

二分查找

查找在算法题中是很常见的,但是怎么最大化查找的效率和写出bugfree的代码才是难的部分。一般查找方法有顺序查找、二分查找和双指针,推荐一开始可以直接用顺序查找,如果遇到TLE的情况再考虑剩下的两种,毕竟AC是最重要的。

一般二分查找的对象是有序或者由有序部分变化的(可能暂时理解不了,看例题即可),但还存在一种可以运用的地方是按值二分查找,之后会介绍。

35. 搜索插入位置

35. 搜索插入位置(简单)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第9张图片

class Solution:
    def searchInsert(self, nums: List[int], target: int) -> int:
        l = 0
        r = len(nums)-1

        while l<=r:
            mid = (r-l)//2 + l
            if nums[mid]==target:
                return mid
            elif nums[mid]<target:
                l = mid+1
            else:
                r = mid-1
        
        return l

540. 有序数组中的单一元素

540. 有序数组中的单一元素(中等)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第10张图片
方法一:
依次遍历,判断

class Solution:
    def singleNonDuplicate(self, nums: List[int]) -> int:
        
        i = 0
        while i<len(nums)-1:
            if nums[i]!=nums[i+1]:
                return nums[i]
            i += 2
        return nums[-1]

复杂度分析:
时间复杂度:最坏情况下,为O(N)
空间复杂度:常数

方法二:
mid=(r-l)//2+l
如果mid为偶数,说明mid之前的元素个数为偶数:
如果nums[mid]==nums[mid+1],则单一元素在右侧,即l=mid+1
如果nums[mid]!=nums[mid+1],则单一元素在左侧,即r=mid(nums[mid]可能是单一元素)

如果mid为奇数,说明mid之前的元素个数为奇数:
如果nums[mid]==nums[mid-1],则单一元素在右侧,即l=mid+1
如果nums[mid]!=nums[mid-1],则单一元素在左侧,即r=mid

注意边界条件,当 mid + 1 超出边界时,说明单一元素是数组的最后一个元素。

class Solution:
    def singleNonDuplicate(self, nums: List[int]) -> int:
        l = 0
        r = len(nums)-1
        while l<r:
            mid = (r-l)//2+l
            if mid+1>=len(nums):
                return nums[mid]
            if mid%2==0:
                if nums[mid]==nums[mid+1]:
                    l=mid+1
                else:
                    r=mid
            else:
                if nums[mid]==nums[mid-1]:
                    l=mid+1
                else:
                    r=mid
        return nums[l]

方法三: 巧用异或
如果mid是偶数,那么和1异或的话,那么得到的是mid+1,如果mid是奇数,得到的是mid-1

class Solution:
    def singleNonDuplicate(self, nums: List[int]) -> int:
        l = 0
        r = len(nums)-1
        while l<r:
            mid = (r-l)//2+l
            if mid+1>=len(nums):
                return nums[mid]
            if nums[mid]==nums[mid ^ 1]:
                l=mid+1
            else:
                r=mid

        return nums[l]

410. 分割数组的最大值

按值二分
410. 分割数组的最大值(困难)
Datawhale编程实践LeetCode分类练习——Task03:查找1之查找表/二分查找(Python)_第11张图片
求最大值最小,考虑二分法
注意:连续子数组

class Solution:
    def splitArray(self, nums: List[int], m: int) -> int:
        
        def helper(mid):
            res=tmp=0
            for num in nums:
                if tmp+num<=mid:
                    tmp+=num
                else:
                    res += 1
                    tmp = num
            return res+1
        
        l=max(nums)
        r=sum(nums)
        while l<r:
            mid = (r+l)//2 
            if helper(mid)>m:
                l = mid+1
            else:
                r = mid
        return l

类似问题
875. 爱吃香蕉的珂珂(中等)
LCP 12. 小张刷题计划(中等)
1482. 制作 m 束花所需的最少天数(中等)
1011. 在 D 天内送达包裹的能力

参考liweiwei1419

你可能感兴趣的:(LeetCode,Datawhale零基础入门,python,leetcode)