zoukankan      html  css  js  c++  java
  • 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 迭代器的用发 可以学习一个

  • 相关阅读:
    Siege 3.0 正式版发布,压力测试工具
    Pomm 1.1.2 发布,专为 PG 设计的 ORM 框架
    Whonix 0.5.6 发布,匿名通用操作系统
    国内开源 java cms,Jspxcms 2.0 发布
    EZNamespaceExtensions.Net v2013增加对上下文菜单、缩略图、图标、属性表的支持
    GNU Guile 2.0.9 发布,Scheme 实现
    jdao 1.0.4 发布 轻量级的orm工具包
    OpenSearchServer 1.4 RC4 发布
    Percona Server for MySQL 5.5.3030.2
    Samba 4.0.5 发布
  • 原文地址:https://www.cnblogs.com/sfzyk/p/9577186.html
Copyright © 2011-2022 走看看