🔞565.数组嵌套
核心:
本题可以把每个元素看作图上一个点,每个点都有一条出度边和一条入度边
笔者认为使用标记法来解决这道题是一个不错的办法,使用max函数不断更新Max值,最后返回答案即可
但这种情况当时让笔者开始怀疑:到底是否可以用标记法呢?
🤷♂️笔者在做这道题时被下图这种情况迷惑了一段时间
事实上这个题是完全可以使用标记法的,如图所示,元素1入度加出度总共为3,与入度+出度=2
相违背。
由此我们得出结论:
1. 每个结点都有一个出度边和一个入度边
2. 将数组抽象为图后,图中 若干节点 一定可以组成若干个 独立的环
3. 结合1和2不难将问题转化为:查找这若干个环里的最大长度。
下面提供两种代码思路进行解题
深度优先算法如果难以理解,可以参考第一种方式 (两者的核心是一样的)
👊暴力遍历法+标记位置:
class Solution {
public:
int arrayNesting(vector<int>& nums) {
int len = nums.size();
vector<int> exits(len, 0); // 设置访问数组
int cur,cnt = 0;
int Max = 0;
for(int i = 0; i < len; ++i) { // 看似双层循环,实际上过程已经被简化
if(exits[i] == 1) { // 如果已经被访问,跳过这次循环
continue;
}
int cur = i; // 设置当前游标
while(!exits[cur]) { // 查看是否已被访问
++cnt;
exits[cur] = 1; // 设置已访问状态
cur = nums[cur]; // 更新cur
}
Max = max(Max, cnt);
cnt = 0;
}
return Max;
}
};
🤦♀️DFS深度优先搜索:
// DFS 采用涂色法进行标记
// 代码来自 英雄哪里出来
class Solution {
int Max, Cnt;
int hash[200010];
void dfs(vector <int>& nums, int u, int color) {
if(hash[u] != -1) { // 该点已经被访问
return ; // 如果程序执行到这里,相当于一个回路已经走完了,回到了初始节点
}
hash[u] = color;
++Cnt;
dfs(nums, nums[u], color);
}
public:
int arrayNesting(vector<int>& nums) {
int i;
int n = nums.size();
int color = 0;
Max = 0;
memset(hash, -1, sizeof(hash));
for(i = 0; i < n; ++i) {
// 已经访问过的点如果再访问,一定有Cnt <= Max
if(-1 == hash[i]) { // 注意,已经访问过的数组不需要再访问了,如果没有这句话
// 复杂度将上升为O(n^2)
Cnt = 0;
dfs(nums, i, ++color);
Max = max(Max, Cnt);
}
}
return Max;
}
};