如何解决如何通过从头到尾移动 N 个元素来旋转数组?
我正在尝试使用 C# 将数组中的多个元素移动到末尾。
我有一个数组(在我的例子中是一个字符数组)和一个整数 z
。现在我想将 z
个字符移到另一个数组的末尾,其他字符应该移到数组的开头。
因此,如果第一个数组是 {'H','E','L','O'}
和 z = 3
,则新数组应该是 {'L','O','H','L'}
。
我希望有人能帮助我。
最佳尝试:
static char[] rotate(char[] c,int z)
{
char[] nc = new char[c.Length];
for (int i = z; i < c.Length; i++)
{
nc[i - z] = c[i];
}
for (int i = 0; i < z; i++)
{
nc[i + z] = c[i];
}
return nc;
}
解决方法
只需使用 Array.Copy
将一个 Array 中的一系列元素复制到另一个 Array 并执行 根据需要键入转换和装箱。
public static void DoStuff<T>(T[]source,int z)
{
var start = source[0..z];
Array.Copy(source,z,source,source.Length - z);
Array.Copy(start,source.Length - z,z);
}
测试
var chars = "asdfghjk".ToCharArray();
DoStuff(chars,3);
Console.WriteLine(string.Join(",",chars));
迭代器的另一种方式
public static IEnumerable<T> DoStuff<T>(T[]source,int z)
=> source.Select((t,i) => source[(i + z) % source.Length]);
或者使用 for 循环
public static T[] DoStuff<T>(T[]source,int z)
{
var result = new T[source.Length];
for (int i = 0; i < source.Length; i++)
result[i] = source[(i + z) % source.Length];
return result;
}
超级高效的零分配
public static unsafe void DoStuff(char[] source,int z)
{
var start = stackalloc char[source.Length];
fixed (char* pArray = source)
{
Buffer.MemoryCopy(pArray,start,z*sizeof(char),z * sizeof(char));
Buffer.MemoryCopy(pArray+z,pArray,(source.Length-z)*sizeof(char),(source.Length - z) * sizeof(char));
Buffer.MemoryCopy(start,pArray+ (source.Length - z),z * sizeof(char),z * sizeof(char));
}
}
输出
f,g,h,j,k,a,s,d
注意:这缺少合适的输入验证和范围检查,以及一个描述性名称。我会把它留给你
,问题在于您代码中的错误索引。
这是固定版本:
static char[] rotate(char[] c,int z)
{
char[] nc = new char[c.Length];
for (int i = z; i < c.Length; i++)
{
nc[i - z] = c[i];
}
for (int i = 0; i < z; i++)
{
nc[i + z - 1] = c[i]; // <-- Change here
}
return nc;
}
然而,更好的解决方案可能是使用 doubly-linked lists 来更好地处理数组项的移动以开始/结束。双向链表的 .NET 实现是 LinkedList Class。 here 你可以找到一些例子来说明如何做到这一点。
,您可以在一行中使用 LINQ 而无需像这样处理数组:
using System.Linq;
var letters = new[] { 'H','E','L','O' };
int posToRotate = 3;
var lettersRotated = letters.Skip(posToRotate).Concat(letters.Take(posToRotate)).ToArray();
Console.WriteLine(new string(lettersRotated));
假设 letters
已分配且不为空。
如果位置超过长度,则什么都不做,但可以先检查以避免处理(也可以检查负索引)。
我们skip前N个字符(取其余),然后我们add我们take的前N个字符。
我们调用 ToArray 是因为 LINQ 适用于 IEnumerable<>(和 IQueryable),所以执行是 deferred 直到这里。
要替换原来的数组,只需写:
letters = letters.Skip(posToRotate).Concat(letters.Take(posToRotate)).ToArray();
输出
LOHEL
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。