• leetcode 854. K-Similar Strings


    给定两个字符串, 判断最少经过多少次swap 可以使得 两个字符串一致,

    首先类似的问题 是存在一个 underlying graph 的。
    每一个字母都对应着一个节点,两个字符串的不一致表示为图上的一条有向边

    最后的问题转化为 图上的最(多)圆环分解

    要注意的是贪心策略并不能解决问题(即每一次都选择 最小的那个圆环构成原图)

    1
    使用记忆化搜索策略。
    将一个所有可能存在路径存在与否的向量作为相应的状态
    超时的代码

    class Solution:
        def kSimilarity(self, A, B):
            """
            :type A: str
            :type B: str
            :rtype: int
            """
            if (A==B): 
                return 0
        
            N = len(A)
            alp ='abcdef'
            
            pairs = [(a,b) for a in alp for b in alp if a!=b]
            # 所有可能的路径
            
            index = {p:i for i,p in enumerate(pairs)}
            # 所有可能的路径的编号
            
            count = [0]*len(index)
            #可能路径的数目(原图) 也就是初始状态
            
            for a,b in zip(A,B):
                if(a!=b):
                    count[index[(a,b)]]= count[index[a,b]]+ 1
            
            seen = set()
            #所有可能出现的环
            for size in range(2,len(alp) + 1):
                for cand in itertools.permutations(alp,size):
                    # 最小的哪一个出发节点为是顺序(防止重复)
                    i = cand.index(min(cand))
                    seen.add (cand[i:]+cand[:i])
            
            possibles = []  #所有可能的环的路径表示 状态之间的 路径
            
            for cand in seen:
                row = [0] * len(alp)*(len(alp)-1)
                for a,b in zip(cand,cand[1:]+cand[:1]):
                    row[index[a,b]]= row[index[a,b]]+1
                
                possibles.append(row)
            ZERO = tuple([0]*len(row))
            memo = {ZERO:0}
            
           # print(possibles)
            def solve(count):
                if count in memo :
                    return memo[count]
                ans =float('-inf')
                #所有可能的路径
                for row in possibles : 
                    count2 = list(count)
                    for i,x in enumerate(row):
                        if count2[i]>=x :
                            count2[i] = count2[i] - x
                        else:
                            break
                    else:
                        ans = max(ans,1 + solve(tuple(count2)))
                memo[count]= ans 
                return ans
        
            return sum(count)-solve(tuple(count))
            
    

    2 暴力进行广度优先搜索
    因为可以证明最优解可以是永远更换第一个不匹配的字母到合适的位置,那么我可以将一个节点的边数目由 N2 下降到N

    而并不是所有意义上的交换 这种复杂度降低是非常有必要的

    结论: 这种数据量比较小的问题往往比较复杂,尤其可能没有多项式解

    class Solution:
        def kSimilarity(self, A, B):
            """
            :type A: str
            :type B: str
            :rtype: int
            """
            def nei(S):
                for i,c in enumerate(S):
                    if c!= B[i]:
                        break
                
                T=list(S)
                for j in range(i+1,len(S)):
                    if(S[j]==B[i]):
                        T[i],T[j]= T[j],T[i]
                        yield "".join(T)
                        T[j],T[i]=T[i],T[j]
            
            queue= collections.deque([A])
            seen ={A:0}
            while(queue):
                S=queue.popleft()
                if(S==B):
                    return seen[S]
                for T in nei(S):
                    if T not in seen:
                        seen[T]=seen[S]+1
                        queue.append(T)
                
    

    这里有一个 fiield 迭代器的用发 可以学习一个

  • 相关阅读:
    数据库常用术语
    灾备模式的基本体系架构
    linux下的c++开发
    视图矩阵的推导-opengl应用
    抓包实例
    以软件推动工业进步 -嵌入式学习网站
    web 前端 转盘界面
    web 汇率
    xml
    高性能网站架构设计之缓存篇(4)- 主从复制
  • 原文地址:https://www.cnblogs.com/sfzyk/p/9577186.html
Copyright © 2020-2023  润新知