在国庆假期的一个傍晚,小悦正在家中享受火锅美食。她嘴里咀嚼着鲜嫩的牛肉,脸上洋溢着满足的微笑。突然,手机铃声响起,打破了这温馨的氛围。她拿起手机一看,是公司打来的电话。

“小悦,有个紧急的项目需要处理,你能来公司加一下班吗?”电话那头传来领导焦急的声音。

小悦顿时嘟起嘴,不太情愿地离开了火锅桌,踏上前往公司的路程。

一到公司,小悦就开始研究领导交给她的任务:处理一个关于小视频螺旋排序算法的问题。这个问题让她感到有些棘手,但她知道没有退缩的余地。于是,她深吸了一口气,开始认真地研究问题。

在图像处理中,螺旋排序算法是一个非常有用的工具。通过将图像按照螺旋顺序排列,可以更方便地对图像进行处理和分析。例如,可以将图像分成多个小块进行特征提取、图像压缩等操作。小悦明白,要解决这个问题,首先需要理解螺旋排序算法的原理。

她开始在纸上画出图像的分块示意图,尝试寻找规律。经过一番推导和实践,她逐渐掌握了螺旋排序算法的核心思想。接着,她开始编写代码来实现这个算法。

时间在悄然流逝,窗外的夜幕渐渐降临。尽管劳累了一天,但小悦的心情却渐渐变得愉悦起来。她在解决问题的过程中感受到了挑战的乐趣和收获的喜悦。当她最终完成代码并成功运行出结果时,她的心中充满了成就感。

“终于解决了!”小悦长出一口气,脸上露出了满意的微笑。她收拾好东西,准备离开公司。走出办公室的那一刻,她抬头看到夜空中繁星点点,心中不禁感慨万分。这个国庆假期,或许没有如愿以偿地休息和放松,但她却在工作中取得了宝贵的进步。

回到家中,小悦继续享受火锅美食。她夹起一块牛肉放进嘴里,细细品味着它的鲜美。这个国庆假期,虽然没有游山玩水的快乐,但她却收获了成长和充实。

小悦面临的问题如下:给定一个n乘n二维数组,按照从最外层元素到中间元素的顺序,排序,顺时针移动,返回排序后的一维数组。

示例:

array = [[1,2,3],
[4,5,6],
[7,8,9]]
snail(array) #=> [1,2,3,6,9,8,7,4,5]

图解:

 


算法实现1:

 1 public static int[] Snail(int[][] array)
2 {
3 // 获取数组的长度
4 int l = array[0].Length;
5 // 创建一个用于存储排序后元素的数组
6 int[] sorted = new int[l * l];
7 // 递归调用 Snail 方法进行螺旋排序
8 Snail(array, -1, 0, 1, 0, l, 0, sorted);
9 // 返回排序后的数组
10 return sorted;
11 }
12
13 public static void Snail(int[][] array, int x, int y, int dx, int dy, int l, int i, int[] sorted)
14 {
15 // 如果数组长度为 0,则直接返回
16 if (l == 0)
17 return;
18 // 循环遍历当前层的元素
19 for (int j = 0; j < l; j++)
20 {
21 // 更新当前元素的坐标,并将其存储到排序数组中
22 x += dx;
23 y += dy;
24 sorted[i++] = array[y][x];
25 }
26 // 递归调用 Snail 方法进行下一层的螺旋排序
27 Snail(array, x, y, -dy, dx, dy == 0 ? l - 1 : l, i, sorted);
28 }

假设我们有一个二维数组array,其中包含了3行3列的整数。数组的内容如下:

1 2 3
4 5 6
7 8 9

我们希望通过螺旋排序算法将这个二维数组按照螺旋顺序排列,并得到一个结果数组r,其中包含按照螺旋顺序排列的元素。结果数组的内容如下:

1 2 3 6 9 8 7 4 5

我们将调用Test方法来测试螺旋排序算法。在Test方法中,首先将二维数组array转换为字符串,并将结果与预期的结果数组r进行比较。如果转换后的字符串与预期结果字符串相等,则测试通过;否则,测试失败。

接下来,让我们详细解释一下螺旋排序算法的运行过程:

  1. 首先,算法会初始化一个空的结果数组snail,用于存储按照螺旋顺序排列的元素。

  2. 然后,算法会定义四个变量:topbottomleftright,分别表示当前螺旋排序的上边界、下边界、左边界和右边界。初始时,top为0,bottom为2,left为0,right为2。

  3. 接着,算法会进入一个循环,直到上边界大于下边界或左边界大于右边界为止。

  4. 在每一次循环中,算法会按照螺旋顺序遍历数组的四条边,并将遍历到的元素添加到结果数组snail中。

  5. 首先,算法会从左到右遍历上边界,并将遍历到的元素添加到结果数组snail中。在这个测试用例中,遍历到的元素为1 2 3

  6. 然后,算法会将上边界下移一行,即top++,此时上边界变为1。

  7. 接着,算法会从上到下遍历右边界,并将遍历到的元素添加到结果数组snail中。在这个测试用例中,遍历到的元素为6 9

  8. 然后,算法会将右边界左移一列,即right--,此时右边界变为1。

  9. 接着,算法会从右到左遍历下边界,并将遍历到的元素添加到结果数组snail中。在这个测试用例中,遍历到的元素为8 7

  10. 然后,算法会将下边界上移一行,即bottom--,此时下边界变为1。

  11. 接着,算法会从下到上遍历左边界,并将遍历到的元素添加到结果数组snail中。在这个测试用例中,遍历到的元素为4

  12. 最后,在这个测试用例中,算法会发现左边界大于右边界,因此跳出循环。

  13. 最后,算法会返回结果数组snail,其中包含按照螺旋顺序排列的元素。在这个测试用例中,返回的结果数组为1 2 3 6 9 8 7 4 5

  14. Test方法中,我们将转换后的结果数组与预期的结果数组进行比较。如果它们相等,则测试通过;否则,测试失败。


算法实现2:

 1     public static int[] Snail(int[][] grid)
2 {
3 var result = new List<int>();
4
5 //通过grid.SelectMany(row => row).Any()判断二维数组grid是否为空。如果为空,则直接返回空的结果数组。
6 if (!grid.SelectMany(row => row).Any())
7 return result.ToArray();
8
9 //将二维数组的第一行添加到结果数组中
10 result.AddRange(grid.First());
11
12 //将二维数组的最右一列(除去第一行)添加到结果数组中
13 result.AddRange(grid.Skip(1).Select(row => row.Last()));
14
15 //将二维数组的最后一行(除去第一行和最后一个元素)逆序添加到结果数组中
16 result.AddRange(grid.Last().Reverse().Skip(1));
17
18 //将二维数组的最左一列(除去第一行、最后一行和第一个元素)逆序添加到结果数组中
19 result.AddRange(grid.Skip(1).SkipLast(1).Select(row => row.First()).Reverse());
20
21 var newGrid = grid
22 .Skip(1)
23 .SkipLast(1)
24 .Select(row => row
25 .Skip(1)
26 .SkipLast(1)
27 .ToArray())
28 .ToArray();
29
30 //通过递归调用Snail方法,将去掉了二维数组的第一行、最后一行、第一列和最后一列后的新二维数组传入,并将返回的结果数组添加到当前的结果数组中
31 result.AddRange(Snail(newGrid));
32
33 return result.ToArray();
34 }

这段代码的逻辑与算法1的功能相同,只是在创建新二维数组newGrid时,使用了链式调用的方式来去掉边界元素。

AddRange 是一个常用在 LINQ 中的方法,通常在 List<T> 或 Dictionary<TKey, TValue> 等集合类型中使用。这个方法用于将另一个集合中的元素添加到当前集合中。

首先,代码通过Skip(1)去掉了第一行,然后通过SkipLast(1)去掉了最后一行,接着通过Select(row => row.Skip(1).SkipLast(1).ToArray())去掉了每一行的第一个元素和最后一个元素,最后通过ToArray()将结果转换为新的二维数组。这样,递归调用Snail方法时传入的新二维数组就是去掉了边界的数组。


假设我们有一个100x100像素的图像,我们想要将其分成10x10个小块进行特征提取或图像压缩。在没有使用螺旋排序算法之前,我们可以按照图像的行优先顺序将像素按顺序分成小块。这意味着我们首先将图像的第一行的前10个像素作为第一个小块,然后是第一行的下一个10个像素作为第二个小块,依此类推,直到图像的第10行。然后,我们继续将图像的第11行的前10个像素作为第11个小块,以此类推,直到图像的最后一行。

这种方法的问题是,它没有考虑到图像的局部结构。相邻的像素在图像中可能是相关的,而按行顺序分块可能会将相关的像素分散在不同的块中。这可能导致特征提取或图像压缩的结果不够准确或失真。

现在,如果我们使用螺旋排序算法来分块图像,我们可以更好地保留图像的局部结构。螺旋排序算法按照螺旋顺序遍历图像的像素,并将它们分成小块。这意味着我们首先将图像的中心像素作为第一个小块,然后按照螺旋顺序将相邻的像素添加到下一个小块,直到所有像素都被分到小块中。

通过使用螺旋排序算法,我们可以更好地保留图像的局部结构,因为相邻的像素通常在空间上也是相邻的。这有助于提高特征提取或图像压缩的准确性和质量。

所以螺旋排序算法在各个领域都有一定的应用价值,可以帮助提高数据处理和分析的效率,优化系统设计和布局,以及改善数据的可视化效果:

  1. 图像处理:在图像处理中,螺旋排序算法可以用于对图像进行分块处理。通过将图像按照螺旋顺序排列,可以更方便地对图像进行处理和分析。例如,可以将图像分成多个小块进行特征提取、图像压缩等操作。

  2. 数据存储和检索:螺旋排序算法可以用于对二维数组或矩阵进行存储和检索。通过按照螺旋顺序对数据进行排序,可以提高数据的访问效率。例如,在二维地图导航系统中,可以将地图数据按照螺旋顺序进行存储,以便快速检索和显示地图信息。

  3. 数据可视化:螺旋排序算法可以用于数据可视化,特别是对于二维数据的可视化。通过按照螺旋顺序对数据进行排序,可以将数据按照一定的规律展示出来,更直观地观察数据的分布和变化。例如,在热力图中,可以按照螺旋顺序对温度数据进行排序,以便更清晰地显示温度的变化趋势。

  4. 电路布局:在电路设计中,螺旋排序算法可以用于电路布局的优化。通过按照螺旋顺序对电路元件进行排序,可以减少电路布线的长度和复杂度,提高电路的性能和可靠性。


测试用例:

  1 using NUnit.Framework;
2 using System;
3 using System.Linq;
4 public class SnailTest
5 {
6
7 private int[] Tsnail(int[][] array)
8 {
9 int[] sorted = new int[array.Length * array.Length];
10 Tsnail(array, -1, 0, 1, 0, array.Length, 0, sorted);
11 return sorted;
12 }
13
14 private void Tsnail(int[][] array, int x, int y, int dx, int dy, int l, int i, int[] sorted)
15 {
16 if (l == 0)
17 return;
18 for (int j = 0; j < l; j++)
19 {
20 x += dx;
21 y += dy;
22 sorted[i++] = array[y][x];
23 }
24 Tsnail(array, x, y, -dy, dx, dy == 0 ? l - 1 : l, i, sorted);
25
26 }
27
28 public string Int2dToString(int[][] a)
29 {
30 return $"[{string.Join("\n", a.Select(row => $"[{string.Join(",", row)}]"))}]";
31 }
32
33 public void Test(int[][] array, int[] result)
34 {
35 var text = $"{Int2dToString(array)}\nshould be sorted to\n[{string.Join(",", result)}]\n";
36 Console.WriteLine(text);
37 Assert.AreEqual(result, SnailSolution.Snail(array));
38 }
39
40 [Test]
41 public void SnailTest1()
42 {
43 int[][] array =
44 {
45 new []{1, 2, 3},
46 new []{4, 5, 6},
47 new []{7, 8, 9}
48 };
49 var r = new[] { 1, 2, 3, 6, 9, 8, 7, 4, 5 };
50 Test(array, r);
51 }
52
53 [Test]
54 public void SnailTest2()
55 {
56 int[][] array =
57 {
58 new []{1, 2, 3, 9},
59 new []{4, 5, 6, 4},
60 new []{7, 8, 9, 1},
61 new []{1, 2, 3, 4}
62 };
63 var r = new[] { 1, 2, 3, 9, 4, 1, 4, 3, 2, 1, 7, 4, 5, 6, 9, 8 };
64 Test(array, r);
65 }
66
67 [Test]
68 public void SnailTest2Empty()
69 {
70 int[][] a = { new int[] { } };
71 Test(a, new int[0]);
72 }
73
74 [Test]
75 public void SnailTestOne()
76 {
77 int[][] a = { new[] { 1 } };
78 Test(a, new[] { 1 });
79 }
80
81
82 [Test]
83 public void SnailRandomTest()
84 {
85 Console.WriteLine("Random Tests");
86 Random rand = new Random();
87 for (int n = 0; n < 100; n++)
88 {
89 var l = rand.Next(1, 31);
90 var array = new int[l][];
91 for (int i = 0; i < l; i++)
92 {
93 array[i] = new int[l];
94 for (int j = 0; j < l; j++)
95 array[i][j] = rand.Next(1, 1001);
96 }
97 Test(array, Tsnail(array));
98 }
99 }
100 }

【算法】国庆加班,火锅与Linq.AddRange的奇妙螺旋的更多相关文章

  1. HR别掉坑里了,送你最精确的计薪算法!

      月工资的计算方式有多种多样.即便是资深的HR,也会犯常识性的错误,正算反算,哪一个方法更适合,有时还会容易出现数字偏差,回想一下,你们公司的工资是如何计算的? 第一 劳动工资计算标准按几天计算 根 ...

  2. Linq快速入门——扩展方法

    Linq为我们提供了许多扩展方法,方便我们对数据源进行操作(Where,Select...).即使你不了解算法,也能使用Linq当回牛人.扩展方法本质并不是什么高深的技术,说白了就是一个Static静 ...

  3. Linq基础必备

    1.linq基础必备之对象初始化器和匿名类型因果分析   3. 一:对象初始化器 1.就是在new的时候给公共属性赋值的一种方式 2. 在没有初始化器之前的时候,我们是怎么初始化的呢??? 1. 构造 ...

  4. ZIP 算法详解 (转!)

    zip 的压缩原理与实现(lz77 算法压缩) 无损数据压缩是一件奇妙的事情,想一想,一串任意的数据能够根据一定的规则转换成只有原来 1/2 - 1/5 长度的数据,并且能够按照相应的规则还原到原来的 ...

  5. .NET入行之工作后

    成长这条路上,有一些事已经渐渐的消失模糊的脑海里,而有一些事,则历历在目,终生铭记. 一切都是从大二下学期快结束的那段培训课程开始的,从此也算是入门了,这也是一条不归路. 在.NET入行之工作前一文中 ...

  6. Cocos2d-x Lua游戏开发Mac环境搭建以及一点点感悟

    接触Cocos2d-x 最近由于公司项目的需要,自己开始接触Cocos,开始做一些简单的轻量级的游戏,以前没有接触过这一块的东西,也是借助这个机会学习一下游戏的开发,由于以前自己接触的全都是iOS和A ...

  7. Cocos 2d-X Lua游戏开发Mac环境搭建以及一点点感悟

    接触Cocos2d-x 最近由于公司项目的需要,自己开始接触Cocos,开始做一些简单的轻量级的游戏,以前没有接触过这一块的东西,也是借助这个机会学习一下游戏的开发,由于以前自己接触的全都是iOS和A ...

  8. [转帖]linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习)

    linux常用命令大全(linux基础命令入门到精通+实例讲解+持续更新+命令备忘录+面试复习) https://www.cnblogs.com/caozy/p/9261224.html 总结的挺好的 ...

  9. UOJ #56. 【WC2014】非确定机

    题意大意:给出一个输出文件,求输入. 1.满足所求的输入文件是一张图,n个点,m条边,所用算法是k(k在给出的输出文件中给出了) 2.算法是图论算法?!k基本上→两位数组成,若十位数相同,说明基本算法 ...

  10. 1804 小C的多边形

    1804 小C的多边形 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 小C偶然发现了一个奇妙的n个点的多边形.现在你需要给外圈的边标记上1~n-1,里圈的边也标记 ...

随机推荐

  1. Kubernetes(k8s)网络策略NetworkPolicy

    目录 一.系统环境 二.前言 三.网络策略(NetworkPolicy)简介 四.创建pod和svc 五.没有网络策略的条件下访问pod 六.给pod添加网络策略 6.1 入站网络策略 6.1.1 入 ...

  2. facebook搜索中的EBR检索技术-学习笔记

    简介 本文是论文Embedding-based Retrieval in Facebook Search的学习笔记 FB的社交搜索 搜索无处不在,搜索的种类多种多样,谷歌.百度.bing的全网搜索.淘 ...

  3. ChatGPT+Mermaid自然语言流程图形化产出小试

    ChatGPT+Mermaid语言实现技术概念可视化 本文旨在介绍如何使用ChatGPT和Mermaid语言生成流程图的技术.在现代软件开发中,流程图是一种重要的工具,用于可视化和呈现各种流程和结构. ...

  4. 【技术积累】Linux中的基础知识【一】

    Linux系统是什么 Linux系统是一种开源操作系统,它极具可定制性和灵活性,因此受到了许多人的欢迎.Linux系统以简单,强大和兼容性而著称.它可用于各种设备,从个人计算机到超级计算机,从移动设备 ...

  5. ReactNative原理与核心知识点

    React Native特点 跨平台 使用js写出页面组件代码被React框架统一转成Virtual DOM树,Virtual DOM树是UI结构的一层抽象,可以被转换成任何支持端的UI视图. Rea ...

  6. OAuth2.0andmultifactorauthentication:Howtocreateasecure

    目录 1. 引言 2. 技术原理及概念 2.1. 基本概念解释 2.2. 技术原理介绍 2.3. 相关技术比较 3. 实现步骤与流程 3.1. 准备工作:环境配置与依赖安装 随着数字化时代的到来,人们 ...

  7. 全球权威的 IT 研究公司 Gartner,发布未来五大隐私趋势

    Gartner(高德纳) 公司是全球最具权威的 IT 研究与顾问咨询公司之一,它成立于 1979 年,总部设在美国康涅狄克州斯坦福.其研究范围覆盖全部 IT 产业,包括 IT 的研究.发展.评估.应用 ...

  8. php处理emoji表情 存数据库

    PHP 处理emoji表情 存数据库 直接过滤掉 1 function filter_emoji($str) { 2 $regex = '/(\\\u[ed][0-9a-f]{3})/i'; 3 $s ...

  9. 2021-7-7 VUE动态样式

    Vue的动态样式实例1 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> & ...

  10. Java的readBytes是怎么实现的?

    1.前言 众所周知,Java是一门跨平台语言,针对不同的操作系统有不同的实现.本文从一个非常简单的api调用来看看Java具体是怎么做的. 2.源码分析 从FileInputStream.java中看 ...