对 int[] visited 的讨论
对Node节点的定义
在一般情况下,图中的节点通过 id 字段来进行设置。例如,题目中给定图中节点编号为 0 到 n-1,此时可以认为有如下的一个结点类Node
class Node{
public int id;
// 省略构造函数...
}
但是,在用字符表示的矩阵图中,一般有 x 和 y 两个下标,上、下、左、右四种移动方式,此时可以认为结点类Node定义如下
class Node{
public int x;
public int y;
}
另外,在 LeetCode 864 中,出现这样的情况,某个位置点并不是只能访问一次,即可以有条件的重复访问(无论什么情况下,无条件的重复访问必定陷入死循环)。因此需要分析出,在什么情况下允许重复访问是解决问题的开始。这题是在获取到新的锁之后。
对于可重复访问节点的问题,我们需要在基本的节点定义下为节点添加一些额外的信息。基本的节点定义中只包含位置信息,例如 x 和 y;对于可重复访问问题,仅仅只考虑位置关系就会陷入死循环。
假设一个场景,有份公用的共享资源(假设为节点[x,y]),某杠精先占用该资源一段时间(访问[x,y]节点),然后到期后又再次占用该资源(再次访问[x,y]节点),有人对他这种长期占用的行为不满,但是杠精可以有理有据地反驳:这个资源允许我重复访问啊!
因此,规则制定者为了完善可重复访问这一规则,例如:上一次访问的人不可以重复访问。如果为了实现这一效果,就需要在节点的定义中添加一个额外字段:上一次访问人。当然,随着规则的复杂化,这个额外字段可以有多个。这些额外字段和位置信息[x,y]无关,统称为状态信息。
总得来说,可重复访问要避免陷入死循环,所以必定是有条件的可重复访问。所以,可重复访问的完整表述应该是:在不同状态信息下,可以重复访问相同的位置;而在相同的状态信息下,不可以重复访问相同的位置。只有引入状态信息,才能说明今天的我Node n1和昨天的我不是同一个我Node n2,即 n1.equals(n2) === false
。
class Node{
public int x;
public int y;
public int state0;
public int state1;
//...
//也可以直接定义成public int[] states;
}
对 int[] visited 的定义
visited 访问数组需要跟随 Node 节点的定义。visited 数组的最泛化的形式应该是 Map<Node, Object> visited
,如果对于 visited 中保存的值不关心,那么可以退化成 Set<Node> visited
,这和 boolean[] visited
相对应。
而 Map<Node, Object> visited
究竟是 int[] visited
还是 int[][] visited
又或者是 int[][][] visited
则完全取决于包含状态信息在内的 Node 节点如何定义。而map中保存的object值和数组中保存的值对应,具体保存什么东西取决于具体问题。例如,限制每个节点的访问次数不能超过3次,那么visited应该保存节点的访问次数。
总结来说,visited 访问数组并不仅仅表示是否访问某个节点,广义来讲,其可以用来保存每一个状态结点的信息。
状态节点说明不仅仅是位置信息,t1时刻访问[x, y] 节点和 t2 时刻访问 [x, y] 节点,如果包含时间信息,那么[x,y,t1]和[x,y,t2]被认为是两个不同的状态节点。
要保存的节点信息取决于向visited中放入的是什么内容。放入true、false则代表是否访问过该节点;放入访问次数则代表访问该节点的次数;还可以放入一个自定义的类型对象。