IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> Leetcode.457.环形数组是否存在循环之学(三色法+递归求带环问题)思(分析问题+转换问题)结合 -> 正文阅读

[数据结构与算法]Leetcode.457.环形数组是否存在循环之学(三色法+递归求带环问题)思(分析问题+转换问题)结合

Leetcode.457.环形数组是否存在循环之学--三色法+递归求带环问题--思--分析问题+转换问题结合

前言

中等算法难度,记录这个题是为了总结自己前面刷题的不足以及解决环问题的一些经验。

  1. 问题所在
    以前解决问题,总觉得只需要分析问题,转换问题就完了。其实没这么简单。能解决以前那些题,是因为那些题所需的知识,我都牢牢掌握,所以分析问题起来很简单。但是今天碰到的题,我用所掌握的方法却达不到更快的速度,所以我采用了前几天一个找环的思路解决了。
  2. 解决方案
    以上的问题就在刨析问题本身,自己是否具有好的基础知识。而当我们有时,就只需要分析转换问题,然后coding,完事,这就是所谓的思。而没有时,我不应该去死咳,浪费一天时间可能也想不出来。这个时候我应该去学习官方提供的解题思路,掌握其中的解题技巧,举一反三触类旁通,这就是所谓的学。
    所以我需要学思结合去面对所有的算法题,不断积累,不断进步。
  3. 注意事项
    第一次看到三色法+DFS,看懂了代码,但是根本没理解透,无法应用到其他上面去,但是沉下心来,专心看,长时间的专心致志,将每一步装进脑子而不打断,就能吃透算法。
  4. 环问题
    初始化status[]数组,进入递归,未被访问节点为初始化的0,被访问节点设为1,当前正在递归中的节点设为2。这样来快速记录所有状态,这也是我提高速度的关键。
    之前我用status[]存节点状态,0表示未访问,1表示访问过。而正在递归中的节点怎么办?我申请了一个ArrayList(这是我所学知识想的基础想法)去存中途的节点,通过add()和removeAll(自身)去做到记录和更新节点。由于ArrayList这两个方法的原理,是很浪费CPU时间,例如add()时,JVM会重新申请一个新的ArrayList去存以前的元素和当前元素,非常浪费时间。

在这里插入图片描述

二、问题

1、剖析问题

按照游戏规则,nums自己的下标+自己的数=nums下一个下标。 通过节点是否走过来循环,通过取余去循环向前走,走过的节点都记录一下。
判断前方是否与自己异号,若异号,则重新游走。若前方是已访问节点,则重新游走。
用list把当前走过的节点记录起来,当走到list里的节点。(初始想法)
判断此下标是不是当前下标,若是,continue;若不是,则返回true.

2、源代码

public boolean circularArrayLoop(int[] nums) {
		/*
		 * 分析问题 按照游戏规则,nums自己的下标+自己的数=nums下一个下标。 通过节点是否走过来循环,通过取余去循环向前走,走过的节点都记录一下。
		 * 判断前方是否与自己异号,若异号,则重新游走。若前方是已访问节点,则重新游走。 用list把当前走过的节点记录起来,当走到list里的节点。
		 * 判断此下标是不是当前下标,若是,continue;若不是,则返回true.
		 */
		int len = nums.length;
		int[] status = new int[len];
		for (int i = 0; i < len; i++) {
			if (status[i] == 1)
				continue;
			//c为current
			int c = i;
			if (isLoop(c, status, nums)) {
				status[c] = 1;
				return true;
			}
			status[c] = 1;
		}
		return false;
	}

	private boolean isLoop(int c, int[] status, int[] nums) {
		status[c] = 2;
		int len = status.length;
		int next = (c + (nums[c] % len) + len) % len;
		//已判断节点,自己到自己的循环,异号节点,三类按顺序"巧"归一。
		if (status[next] == 1 || c == next || nums[c] * nums[next] < 0)
			return false;
		if (status[next] == 2) {
			return true;
		}
		if (isLoop(next, status, nums)) {
			status[next] = 1;
			return true;
		} else {
			status[next] = 1;
			return false;
		}
	}

三、评估

1、时间复杂度

O(n),n为节点长度。

2、空间复杂度

O(n),n为节点长度

四、更新

进阶挑战
进阶:你能设计一个时间复杂度为 O(n) 且额外空间复杂度为 O(1) 的算法吗?

1、分析

由于我们不是每个节点都要进入循环,这样本身就大大加快了时间,而访问过的节点其实已经就没什么作用了,我把访问了的节点即无用的节点用气来,刚好契合三色法。这样就将空间复杂度提升到O(1)
在这里插入图片描述

2、源代码(用递归)

public boolean circularArrayLoop(int[] nums) {
		/*
		 * 分析问题 按照游戏规则,nums自己的下标+自己的数=nums下一个下标。 通过节点是否走过来循环,通过取余去循环向前走,走过的节点都记录一下。
		 * 判断前方是否与自己异号,若异号,则重新游走。若前方是已访问节点,则重新游走。 用list把当前走过的节点记录起来,当走到list里的节点。
		 * 判断此下标是不是当前下标,若是,continue;若不是,则返回true.
		 */
		int len = nums.length;
		//int[] status = new int[len];
		for (int i = 0; i < len; i++) {
			//-1000<=nums[i]<=1000
			if (nums[i] == 1001)
				continue;
			int c = i;
			if (isLoop(c, nums)) {
				nums[c] = 1001;
				return true;
			}
			nums[c] = 1001;
		}
		return false;
	}

	private boolean isLoop(int c, int[] nums) {
		int len = nums.length;
		int next = (c + (nums[c] % len) + len) % len;
		if (nums[next] == 1002) {
			return true;
		}
		if (nums[next] == 1001 || c == next || nums[c] * nums[next] < 0) {
			return false;
		}
		nums[c] = 1002;
		
		if (isLoop(next, nums)) {
			nums[next] = 1001;
			return true;
		} else {
			nums[next] = 1001;
			return false;
		}
	}

3、源代码(不用递归)

递归太耗时,且递归+三色法每次要修改nums[next] = 1001;

public boolean circularArrayLoop(int[] nums) {
		/*
		 * 分析问题 按照游戏规则,nums自己的下标+自己的数=nums下一个下标。 通过节点是否走过来循环,通过取余去循环向前走,走过的节点都记录一下。
		 * 判断前方是否与自己异号,若异号,则重新游走。若前方是已访问节点,则重新游走。 用list把当前走过的节点记录起来,当走到list里的节点。
		 * 判断此下标是不是当前下标,若是,continue;若不是,则返回true.
		 */
		int len = nums.length;
		for (int i = 0; i < len; i++) {
			if (nums[i] < 1001){
			int c = i,next=i;
            while(true){
                c = next; 
                next = (c+(nums[c]%len)+len)%len;
                if(nums[next] == 1001+i){ 
                     return true;
                } 
                //如果nums[next] == 1001+i就return,所以在这可以简单判断1000 < nums[c],c==next的机会比异号少,把异号排前面
                if(1000 < nums[c] || nums[c] * nums[next] <0  || c==next)
                      break;
                nums[c] = 1001+i;
                
            }
			
		}
        }
		return false;
      
	}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-08-08 11:34:33  更:2021-08-08 11:50:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 18:22:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码