5.15力扣 并查集 位运算 前缀和 带权的图(399)

547 朋友圈
在这里插入图片描述

class union:
    def __init__(self,n):
        self.pre=[i for i in range(n)]
        self.rank=[1 for i in range(n)]
        self.cnt=n
    def find(self,x):
        #注意这里是while,不是if
        while x !=self.pre[x]:
            x=self.pre[x]
        return x
    def union(self,p,q):
        parent_p=self.find(p)
        parent_q=self.find(q)
        if parent_p!=parent_q:
            if self.rank[parent_p]<self.rank[parent_q]:
                self.pre[parent_p]=parent_q
            elif self.rank[parent_p]>self.rank[parent_q]:
                self.pre[parent_q]=parent_p
            else:
                self.pre[parent_q]=parent_p
                self.rank[parent_p]+=1
            self.cnt-=1
        

class Solution:
    def findCircleNum(self, M: List[List[int]]) -> int:
        n=len(M) 
        un=union(n)
        for i in range(n):
            for j in range(n):
                if M[i][j]==1:
                    un.union(i,j)
        return un.cnt
        # res=[]
        # for i in range(n):
        #     root=un.find(i)
        #     if root not in res:
        #         res.append(root)
        # return len(res)

990 等式方程的可满足性
在这里插入图片描述

class union:
    def __init__(self,n):
        self.pre=[i for i in range(n)]
    def find(self,x):
        while x!=self.pre[x]:
            x=self.pre[x]
        return x
    def union(self,p,q):
        if self.connect(p,q):
            return 
        parent_p=self.find(p)
        parent_q=self.find(q)
        if parent_p!=parent_q:
            self.pre[parent_p]=parent_q
    def connect(self,p,q):
        return self.find(p)==self.find(q)

class Solution:
    def equationsPossible(self, equations: List[str]) -> bool:
        n=26
        un=union(n)
        for i in equations:
            if i[1]=='=':
                idx1=ord(i[0])-ord('a')
                idx2=ord(i[3])-ord('a')
                un.union(idx1,idx2)
        for i in equations:
            if i[1]=='!':
                idx1=ord(i[0])-ord('a')
                idx2=ord(i[3])-ord('a')
                #不等式两端属于同一个并查集说明不符合条件
                if un.connect(idx1,idx2):
                    return False
        return True

位运算:
136. 只出现一次的数字
在这里插入图片描述
在这里插入图片描述

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        single_num=0
        for num in nums:
            single_num^=num
        return single_num

137 只出现一次的数字二
在这里插入图片描述
如果所有数字都出现了 3 次,那么每一列的 1 的个数就一定是 3 的倍数。之所以有的列不是 3 的倍数,就是因为只出现了 1 次的数贡献出了 1。所以所有不是 3 的倍数的列写 1,其他列写 0 ,就找到了这个出现 1 次的数。
那么需要我们将数字转为二进制,统计了每一位的 1 的个数。我们使用了一个 32位 的 int 来统计。事实上,我们只需要看它是不是 3 的倍数,所以我们只需要两个 bit 位就够了。初始化为 00,遇到第一个 1 变为 01,遇到第二个 1 变为 10,遇到第三个 1 变回 00 。接下来就需要考虑怎么做到。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
因为一共有三个状态,所以我们需要用两个变量来表示状态。用 once 表示是否在状态 1,用 twice 来表示是否在状态 2 。那么两个变量都为 0 就表示在状态 0 。然后可以得到如下的状态转移表:

作者:godweiyang
链接:https://leetcode-cn.com/problems/single-number-ii/solution/zi-dong-ji-wei-yun-suan-zui-xiang-xi-de-tui-dao-gu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
在这里插入图片描述
b:
在这里插入图片描述
b=~a&(x^b)
a:
在这里插入图片描述
a=~b&(x^a)
由于代码的实现中,每一位的计算并不是并行进行的,所以可以通过画一个行列由a,new_b,x构成的卡诺图来利用先生成的位。
在这里插入图片描述
在这里插入图片描述

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
    #位运算
        # a,b=0,0
        # for num in nums:
        #     b=~a&(b^num)
        #     a=~b&(a^num)
        # return b
        #数学方法
        a=list(set(nums))
        return (sum(a)*3-sum(nums))//2

260. 只出现一次的数字 III
在这里插入图片描述
摘自题解
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        bismark=0
        for num in nums:
            bismark^=num
        diff=bismark&(-bismark)
        x=0
        for num in nums:
            #将数组分为包含两个不同的只出现一次元素的数组,这两个元素肯定有一位不同,当bismark中该位为1时,说明就是该位对于两个元素来说不同的
            if num & diff:
                x ^=num
        return [x,bismark^x]

哈希表:时间、空间复杂度均是O(n)

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        hash=defaultdict(int)
        for num in nums:
            if num not in hash:
                hash[num]=1
            else:
                hash[num]+=1
        return [x for x in hash if hash[x]==1]

645 错误的集合
在这里插入图片描述

class Solution:
    def findErrorNums(self, nums: List[int]) -> List[int]:
        err=sum(nums)-sum(set(nums))
        res=0
        n=len(nums)
        for num in nums:

 - List item

            res^=num
        for i in range(1,n+1):
            res^=i
        return [err,err^res]

399. 除法求值
在这里插入图片描述
带权的图
对每个equation如"a/b=v"构造a到b的带权v的有向边和b到a的带权1/v的有向边,
之后对每个query,只需要进行dfs并将路径上的边权重叠乘就是结果了,如果路径不可达则结果为-1。

class Solution:
    def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]:
        graph=defaultdict(list)
        weight=defaultdict(int)
        for idx,equ in enumerate(equations):
            graph[equ[0]].append(equ[1])
            graph[equ[1]].append(equ[0])
            weight[(equ[0],equ[1])]=values[idx]
            weight[(equ[1],equ[0])]=float(1/values[idx])
        def dfs(start,end,visited):
            #这条边已经存在,则直接输出权值
            if (start,end) in weight:
                return weight[(start,end)]
                #图中没有这个点,用0来表示容易跳出
            if start not in graph or end not in graph:
                return 0
            #已经被访问过
            if start in visited:
                return 0
            visited.append(start)
            for node in graph[start]:
                res=weight[(start,node)]*dfs(node,end,visited)
                #找到第一个结果不为0的就弹出
                if res!=0:
                    #将结果加入,以便于以后使用
                    weight[(start,end)]=res
                    break
            visited.remove(start)
            return res
        res=[]
        for q0,q1 in queries:
            ans=dfs(q0,q1,[])
            #为0,说明不存在,则输出-1
            if ans==0:
                ans=-1.0
            res.append(ans)
        return res

560. 和为K的子数组
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
sum(i,j)=sum(0,j)-sum(0,i),计算到前i个数字和sum(0,i)时,只需要判断sum(0,i)-k是否存在哈希表中,即是否存在sum(i,j)=k,sum(0,i)=sum(0,i)-k,则说明从i-j的连续子数组和为k
利用 hashmap 记录和的累加值来避免重复计算

class Solution:
    def subarraySum(self, nums: List[int], k: int) -> int:
        n=len(nums)
        hash=defaultdict(int)
        #初始化一个0,用于计算从开始到i的累加和刚好是k
        hash[0]=1
        pre=0
        count=0
        for i in range(n):
            pre+=nums[i]
            if pre-k in hash:
                count+=hash[pre-k]
            if pre in hash:
                hash[pre]+=1
            else:
                hash[pre]=1
        return count

523 连续的子数组和
在这里插入图片描述
如果 k = 0, 当且仅当sum[i…j] = 0的时候 i-j之间大于1,return True
如果 k != 0, sum[i…j]是k的倍数的时候,return True
用哈希表记录前缀和对k的余数

class Solution:
    def checkSubarraySum(self, nums: List[int], k: int) -> bool:
        hash=defaultdict(int)
        n=len(nums)
        if n<2:
            return False
        pre=0
        hash[0]=-1
        for i in range(n):
            pre+=nums[i]
            if k!=0:
                pre=pre%k
            if pre in hash:
                #不能用=,防止[0,1,0] 0
                if i-hash[pre]>1:
                    return True
            else:
                hash[pre]=i
        return False

974. 和可被 K 整除的子数组
在这里插入图片描述

class Solution:
    def subarraysDivByK(self, A: List[int], K: int) -> int:
        #用哈希表记录前缀和对K的余数 ,若余数存在则说明这之间的连续数组元素和可以被K整除
        hash=defaultdict(int)
        pre=0
        count=0
        #有些数本身就能整除K,所以需要初始化余数0为1
        hash[0]=1
        n=len(A)
        for i in range(n):
            pre+=A[i]
            if K!=0:
                pre%=K
                if pre in hash:
                    count+=hash[pre]
                    hash[pre]+=1
                else:
                    hash[pre]=1
        return count

713. 乘积小于K的子数组
在这里插入图片描述
在这里插入图片描述
如果一个子串的乘积小于k,那么他的每个子集都小于k
计算[10, 5]这个数组的子串是,只加入[5]和[10, 5],而不加入[10],这部分的子串数量刚好是r - l + 1

class Solution:
    def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int:
        if k<=1:
            return 0
        left,ans=0,1
        count=0
        #right指针一直向右遍历,每次循环找到以nums[r]为结尾的乘积小于k的连续数组个数
        for r,val in enumerate(nums):
            ans*=val
            # left向右移动,直到找到乘积小于k的第一个left,此时left-right之间的数组乘积都小于k
            while ans>=k:
                ans/=nums[left]
                left+=1
            count+=r-left+1
        return count
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
最长公共前缀是指一组字符串中,所有字符串都有的最长的前缀。根据提供的代码,可以看出这是一个用C语言实现的求解最长公共前缀的函数。函数的输入是一个字符串数组和数组的大小,输出是一个字符指针,指向最长公共前缀的起始位置。 这个函数的实现思路是,首先取数组中第一个字符串的第一个字符作为初始比较字符,然后遍历数组中的每个字符串的相同位置的字符,如果有不相同的字符,则退出循环。如果所有字符串的相同位置的字符都相同,则将初始比较字符更新为下一个位置的字符,继续比较下一位置的字符,直到遍历完所有字符串或者找到不相同的字符。最后,将最长公共前缀的末尾字符置为'\0',返回最长公共前缀的起始位置。 这个函数的时间复杂度是O(n*m),其中n是字符串数组的大小,m是最长公共前缀的长度。 #### 引用[.reference_title] - *1* *2* [力扣:最长公共前缀(详解)](https://blog.csdn.net/weixin_73142957/article/details/129778838)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [力扣专题——14. 最长公共前缀——最长公共前缀C语言解法](https://blog.csdn.net/qq_42479987/article/details/116953103)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值