算法设计与分析:K-Similar Strings(Week 5)

本文探讨了如何找到两个字符串A和B的最小交换次数(K),使得通过在A中交换字母位置最多K次可以得到B。提出了一种策略,从左到右检查字符串,寻找能最大化修正效果的交换,并使用递归解决子问题。算法虽然类似BFS,但由于搜索所有可能的节点并在最后取最小值,所以并非典型的BFS。文章提供了Python3的代码实现并展示了测试结果。
摘要由CSDN通过智能技术生成

学号:16340008

题目:854. K-Similar Strings


Question:

Strings A and B are K-similar (for some non-negative integer K) if we can swap the positions of two letters in A exactly K times so that the resulting string equals B.

Given two anagrams A and B, return the smallest K for which A and B are K-similar.

Example 1:

Input: A = "ab", B = "ba"
Output: 1

Example 2:

Input: A = "abc", B = "bca"
Output: 2

Example 3:

Input: A = "abac", B = "baca"
Output: 2

Example 4:

Input: A = "aabc", B = "abca"
Output: 2

Note:

  1. 1 <= A.length == B.length <= 20
  2. A and B contain only lowercase letters from the set {'a', 'b', 'c', 'd', 'e', 'f'}

Answer:

题意是:给A,B两个字符串,在A中两个字母互相交换,求最少交换多少次后能得到B,即相似度K。首先我们可以知道A,B等长,且A必定能通过有限次字母交换后得到B。因此我们为得到最小交换次数,应保证每次交换能修正至少一个或两个(若能做到)字母。我们可以从A字符串左边开始,对字母(下标为i)作如下判断:

  1. 若A[i] == B[i],即A与B在该下标处相等,则对下一个字母进行判断。(保证A[0:i] 与 B[0:i]相等)
  2. 若A[i] != B[i],则在A[i+1:]中找到A[j]与B[i]相同与B[j]不同(否则修正效果为0),记录所有符合条件的下标j。若A[i]又恰好等于B[j],则可直接交换A[i]和A[j],因为这样修正效果为2,必是最优的交换之一。交换后,由于A[0:i+1]与B[0:i+1]这i个数相等,因此我们可调用函数进行递归,对A[i+1:]与B[i+1:]进行对比。调用的函数的返回值+1(此次交换)即为所求。
  3. 定义times为len(A)-1,该times必然大于等于所求次数(只要保证每次交换能修正一个,两完全不相似的字符串在times次交换后可相等)。遍历记录的每个j,对每个j作如下操作:交换A[i]与A[j],对A[i+1:]与B[i+1:]调用函数本身递归,对其返回值+1与times比较求更小值赋值给times。然后重新交换A[i]与A[j],开始下一个j的操作。结束对每个j的操作后返回times。
  4. 当字符串A长度为1时返回0

这里用到的搜索思路在于第三步的判断,对每个有修正意义交换的状态向下搜索,因此搜索的节点上必然字符串A与B越来越短,当字符串仅剩长度1时返回0(该字符串无需交换)。每个节点都对其子节点的返回次数中取最小值,再加一反馈给上层节点。顶层节点对所有返回值对比取最小即可。算法看似是BFS,然而实际上并不会在得到最小解时便停止搜索,仍然会搜索完可能节点后再比较取最小。

以下为代码(python3):

class Solution:
    def kSimilarity(self, A, B):
        """
        :type A: str
        :type B: str
        :rtype: int
        """
        times = 0
        for i in range(len(A)-1):
            if A[i] == B[i]:
                continue

            container = []
            for j in range(i+1, len(A)):
                if A[j] == B[i] and A[j] != B[j]:
                    container.append(j)
                    if A[i] == B[j]:
                        A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
                        return 1 + self.kSimilarity(A[i+1:], B[i+1:]) 
            
            times = len(A) - 1

            for j in container:
                A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
                times = min(times, 1 + self.kSimilarity(A[i+1:], B[i+1:]))
                A = A[:i] + A[j] + A[i+1: j] + A[i] + A[j+1:] # swap A[i] and A[j]
            
            return times

        return 0

以下代码可用于本地测试:

test = Solution()
A = 'aabc'
B = 'abca'
print(test.kSimilarity(A, B))

以下为LeetCode中测试结果:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值