algorithm - 查找最小幸存者数量的函数
问题描述
给出了不同类型的细胞,它们可以吞噬它们的直接邻居:
- X型可以吞Y型
- Y型可以吞Z型
- Z型什么都不做
计算最小的幸存者人数。
- 单元由一维数组表示。
- 根据上述规则,一个细胞只能吞下指定的类型
- 如果有多种方式,选择最优的,最小化幸存者的数量
## Example:
C=[X,Y,Z,X,Z,Z,Y]
Answer is: 3.
* C0 swallows C1, [X,Z,X,Z,Z,Y]
* C5 swallows C4, then C3 [X,Z,X,Y]
* C2 swallows C3 [X,Z,X]
如何实现这样的功能?
解决方案
我们可以进行以下观察:
- 如果列表没有 Y,那么什么都不能吞下
- 如果列表只有 Y,那么什么都不能吞
- 在所有其他情况下,都有可能吞下某些东西,因为这意味着有一个 Y 有一个不是 Y 的邻居。如果那个邻居是一个 X,那么这个 Y 可以被那个邻居吞下,或者如果那个邻居是Z,那么这个 Y 可以吞掉那个邻居。
- 一个 X 不能被吞下,所以所有的 X 都留下了。
因此,我们应该优先考虑 Y 吞下 Z 的动作。这不会消除 X 吞下 Y 的任何可能性,......所以我们可以推迟这些动作,而不会冒险采取不太理想的路径。
当无法再进行此类移动时,执行唯一剩下的移动类型,即 X 吞下 Y。
如果这一举动也不再可能,我们已经达到了最低限度。
为了确保算法有效,可以将输入存储在链表中。第一步(Y 吞下 Z)可以通过链表一次扫描执行。如果当前节点是 Y 而前一个节点是 Z,则从列表中删除 Z,并保持与当前节点相同的节点用于下一次迭代。如果前一个节点不是 Z,但下一个节点是,则删除下一个节点并保持与当前节点相同的节点用于下一次迭代。如果两者都不成立,则将下一个节点设为当前节点并重复。
这具有线性时间复杂度。
下一阶段(X 吞噬 Y)遵循相同的原则。
执行
我将在这里给出一个 Python 实现。首先遵循使用哨兵节点的通用双向链表的代码:
class Node:
def __init__(self, val, prev=None):
self.val = val
self.prev = prev or self
self.next = prev.next if prev else self
self.next.prev = self.prev.next = self
def remove(self):
self.prev.next = self.next
self.next.prev = self.prev
class LinkedList(Node):
def __init__(self, lst=None):
super().__init__(None) # A sentinel node
if lst:
node = self
for val in lst:
node = Node(val, node)
def values(self):
for node in self.nodes():
yield node.val
def nodes(self):
node = self.next
while node != self:
yield node
node = node.next
实际的算法将如下所示:
def swallow(c):
ll = LinkedList(c) # create doubly linked list for input
for eater, food in ("YZ", "XY"): # two phases
for node in ll.nodes():
if node.val == eater:
while node.prev.val == food:
node.prev.remove()
while node.next.val == food:
node.next.remove()
return list(ll.values()) # return result as a standard list
你可以这样称呼它:
c = ["X","Y","Z","X","Z","Z","Y"]
print(swallow(c)) # ['X', 'X']
替代实施
除了链表,您还可以使用字符串和正则表达式来删除:
- 出现在 Z 之前的任何 Y 序列
- 紧跟在 Z 之后的任何 Y 序列
- 任何出现在 Y 之前的 X 序列
- 紧跟在 Y 之后的任何 X 序列
... 以该顺序。
import re
def swallow(c):
s = "".join(c) # convert to string
s = re.sub(r"Z+Y", "Y", s)
s = re.sub(r"YZ+", "Y", s)
s = re.sub(r"X+Y", "X", s)
s = re.sub(r"YX+", "X", s)
return list(s) # convert back to list
推荐阅读
- java - JPA 查询超时参数被忽略,但 @Transaction 注释有效
- r - 在 R 中的列表列表中的列上分配一个向量
- docker - 如何让 Docker 以 root 身份运行?
- codenameone - iOS 中的侧边菜单和选项卡问题 - cn1
- python - 从cleverhans攻击模型生成对抗数据
- php - 使用 PHP curl 对直接发布 API 进行发布调用时出现 Securepay Invalid Fingerprint 错误
- asp.net-mvc - 想要下载我们已上传以在文件签名上签名的确切文件格式
- git - 如何根据某些文件扩展名获得 2 个分支之间的差异?
- java - Elixir 设计器显示渲染模板失败,而我只是单击模板
- ios - 生成字典函数的问题