力扣457. 环形数组是否存在循环

第六十天 --- 力扣457. 环形数组是否存在循环

题目要求:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

快慢指针法

1、问题的转化

如果题目中给的是单向链表上寻找一个环,那么很简单,我们只需要从起点出发, 看是否出现回头路即可。但是这道题并不是链表结构,而是数组结构,每一个数组索引都存有一个值(非零),它代表他向左或者向右可以走的步数,那么我们这么想,某一个点可以向左向右走到的位置,和该点不正是一个单向边的关系吗,所以所有单向边构成了一个大型链表,我们只需要从每个节点都出发,寻找环路即可,综上:该问题就被转化成了,数组转化为链表,链表上寻找环路的问题。

2、解决方案

寻找环路最基础的想法就是快慢指针法:基础方法讲解见我的另一篇博客单向链表上寻找环

具体代码

1、当从一个点出发,发现没有环路或者不合法的时候,就可以不用再寻找,刚才找过的点已经无意义,这来源于本体的特点,每个数组索引都只能有一个值,即每个节点都只能有一个出边,再根据每个节点的值都是非零的,所以走过的无用节点置零。
2、根据题意,我们能走的是同方向的,非零节点,但是这里注意,快节点一次走两下,必须保证这两下都和慢节点同方向,才符合题意。
3、判断出有环,必须在看是否是长度为1的环,是的话必须干掉。
4、只有找到合法环的时候才能返回真,其余情况将走过的点置零
5、置零的时候,谁被走过是个问题,这么想就行,就是开始的时候快慢指针同一起点出发(题目中的初始值是为了让while循环进行下去,这两种初始值都行),快指针要在getIndex(add)基础上再走一次,所以就必须要求add点和getIndex(add)点二者同方向,快慢指针才会继续走下去,所以条件出来了。

class Solution {
public:
	vector<int> item;
	int n;
	int getIndex(int cur) {//将数组转化成链表结构,获得该节点的下一个节点位置
		return ((cur + item[cur]) % n + n) % n;
	}
	bool circularArrayLoop(vector<int>& nums) {
		n = nums.size();
		item = nums;
		for (int i = 0; i < n; i++) {//遍历每一个节点
			if (!nums[i]) {//访问过的节点
				continue;
			}
			int slow = i, fast = getIndex(i);
			while (nums[slow] * nums[fast] > 0 && nums[slow] * nums[getIndex(fast)] > 0) {//保证快指针两次走的节点方向和慢指针一致
				if (slow == fast) {//当判断出循环了,需要排除长度为一
					if (slow != getIndex(slow)) {
						return true;
					}
					else {//特殊情况,循环长度为一
						break;
					}
				}
				slow = getIndex(slow);
				fast = getIndex(getIndex(fast));
			}
			//将刚才走过的都置零
			 int add = i;
            while (nums[add] * nums[getIndex(add)] > 0) {
                int tmp = add;//这里必须这样写,因为getIndex函数的原因
                add = getIndex(add);
                nums[tmp] = 0;
            }
		}
		return false;
	}
};

(所有代码均已在力扣上运行无误)

经测试,该代码运行情况是(经过多次测试所得最短时间):

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JLU_LYM

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值