[探究] 数组循环移动的一种方式

(笔者为普通高三学生,无竞赛经验,如果你有更好的方法,请忽略本文)

最近刷信息技术做到一道题,设今天是星期 k(k=1,2,3,4,5,6,7)。求昨天是星期几?明天是星期几? 这两个问题看似简单,实则隐含着深意,隐含着一种解决此类问题的思想。

答案是 (k+5)mod7+1。它是如何被推导出来的呢?也许需要严格的数学证明,但是,对于一个追求效率的人来说,那些证明实在是繁冗拖沓,下面我提供一种很快的解决办法:

我称之为“启发推导法”。大概记得这种方法老师之前上课讲过,不过他研究得肯定没我透彻。“启发”的意思是,从一个猜测的答案开始,根据逻辑推理,逐渐达到正确的解。

 

  • PART1-求“明天是星期几”

按照习惯性思维,我们应该很快能写出 (k+1)mod7 。这个公式在 k 为 157 时符合得很好,但是对 k=6 时就无能为力了,为什么呢?因为对 7 取模的结果最大只能是 6 。从逻辑上这个公式就被推翻了——但它已经很接近正确的解了,确切地来说已经满足了 67 的情况。怎么让结果能覆盖到 7 呢?只需要加上一个 1 就行了,但是别忘了在括号内减去加上的 1。即:kmod7+1

它的确是符合所有的情况的。

  • PART2-求“昨天是星期几”

对于这类情况的处理稍显复杂,同样我们先写出 (k1)mod7 ,但它显然不行,范围里就没有 7 。怎么做呢?还是括号外 +1 ,括号内 1 吗?这样 k 代进去就是负数了。

我们知道对一个数取模时,加上它本身对取模结果没有影响,不妨先 +7 以防止负数的出现?即 (k+6)mod7,再按照原来的方法处理,就成了 (k+5)mod7+1,符合所有情况。


上面只是一个引子,现在我们回归正题——实现数组的循环移动。

无疑,这个操作需要额外的存储空间,因为一个元素的移动必然引起一系列元素的连锁移动,不能直接覆盖否则数据会丢失。考虑一个数组 a ,它存放着待循环移动的数据,现在我们开一个数组 b 来存放循环移动后的数据,此时就需要用到引子里面的思想方法,不多说,直接呈上代码:

复制代码
#include <vector>
#include <iostream>

void printArray(const std::vector<int> &v)
{
    for (const auto& object : v)
        std::cout << object << " ";
    std::cout << std::endl;
}

int main()
{
    std::vector<int> a{ 1,2,3,4,5,6,7,8 };
    int n = a.size(); // a数组的元素个数
    int m = 1; // 循环向右移动m个元素
    std::vector<int> b(n, 0);

    std::cout << "Array A: ";
    printArray(a);
    std::cout << std::endl;

    for (; m < n; m++)
    {
        for (int i = 0; i < a.size(); i++)
            b[(i + m - 1) % n + 1] = a[i];
        std::cout << "Array B: ";
        printArray(b);
    }
    return 0;
}
复制代码

 

 运行代码,却发现结果和预期不符,为什么呢?因为我们前面的公式是针对 1n 的。

但是,不说以不变应万变,但只要稍作改动—— 0n1 不就是 1n 吗? 我们可以先 +1 ,将其代入公式,再 1 恢复原状:

for (; m < n; m++)
    {
        for (int i = 0; i < a.size(); i++)
            b[(i + m) % n] = a[i];
        std::cout << "Array B: ";
        printArray(b);
    }

 

同样地,左移的代码也就顺理成章:

for (; m < n; m++)
    {
        for (int i = 0; i < a.size(); i++)
            b[(i - m % n + n) % n] = a[i]; // m % n 防止索引为负数
        std::cout << "Array B: ";
        printArray(b);
    }

 

现在我们来考虑一个变形,之前一直都是对 a[i] 赋值,能不能对 b[i] 赋值呢?其实原理完全一样,此处不再赘述。

--END--  距离第一次选考还有 40 天。


UPD(2023-04-28):更新了 LATEX 。(感觉我上大学的这两年(自)学的东西比过去十几年的都多...)

 

posted @   ZXPrism  阅读(150)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示