408真题解析-2010-42-数据结构-数组循环左移

408真题解析-2010-42-数据结构-数组循环左移

一 真题2010-42

2010-42(13分) 设将 $ n ( ( n>1 $)个整数存放到一维数组 $ R $ 中。试设计一个在时间和空间两方面都尽可能高效的算法,将 $ R $ 中保存的序列循环左移 $ p ( ( 0 < p < n $)个位置,即将 $ R $ 中的数据由 $ (x_0, x_1, \ldots, x_{n-1}) $ 变换为 $ (x_p, x_{p+1}, \ldots, x_{n-1}, x_0, x_1, \ldots, x_{p-1}) $。要求:

  1. 给出算法的基本设计思想。
  2. 根据设计思想,采用 C、C++或Java语言描述算法,关键之处给出注释。
  3. 说明你所设计算法的时间复杂度和空间复杂度。

二 题目要素解析

核心考点

数组循环左移(右旋 / 左旋)、三次反转法、时间空间复杂度优化。

考查知识点
  1. 数组就地逆置(反转)操作。
  2. 循环移位问题的最优解法:三次反转法
  3. 时间复杂度 O(n),空间复杂度 O(1) 的设计要求。
  4. 算法设计题的标准答题结构:思想 + 代码 + 复杂度。
题型特征

数组操作、原地(in-place)修改、严禁开新数组、高效。

易错点
  1. 使用额外数组(空间 O(n),直接扣分)。
  2. 左移 p 位时,分界点错误。
  3. 反转区间写错:前 p 个、后 n−p 个、整体。
大纲 / 教材对应

数据结构 – 线性表 – 顺序表(数组)操作。

三 哔哔详解

算法基本思想(三次反转法)

利用数组反转的性质实现原地循环移位:

  1. 反转前 $ p $ 个元素:$ [x_0, \ldots, x_{p-1}] \rightarrow [x_{p-1}, \ldots, x_0] $
  2. 反转后 $ n-p $ 个元素:$ [x_p, \ldots, x_{n-1}] \rightarrow [x_{n-1}, \ldots, x_p] $
  3. 反转整个数组:$ [x_{p-1}, \ldots, x_0, x_{n-1}, \ldots, x_p] \rightarrow [x_p, \ldots, x_{n-1}, x_0, \ldots, x_{p-1}] $

💡 数学原理

设原数组为 $ AB $ ($ A $ 为前 $ p $ 个元素,$ B $ 为后 $ n-p $ 个元素),目标为 $ BA $。

通过 $ \text{reverse}(A) \cdot \text{reverse}(B) = A^r B^r $,再 $ \text{reverse}(A^r B^r) = (A^r Br)r = BA $。

📌 示例演示( n=7,p=3n=7,p=3 )

初始: [1, 2, 3, 4, 5, 6, 7]   (A=[1,2,3], B=[4,5,6,7])
步骤1: [3, 2, 1, 4, 5, 6, 7]   (反转A)
步骤2: [3, 2, 1, 7, 6, 5, 4]   (反转B)
步骤3: [4, 5, 6, 7, 1, 2, 3]   (反转整体) → 成功!

四 参考答案

1)算法基本设计思想

采用三次反转法

  • 第一步:反转数组前 pp 个元素;
  • 第二步:反转数组后 n−pn−p 个元素;
  • 第三步:反转整个数组。
    最终实现循环左移 pp 位,且无需额外空间。

2)C语言代码实现

// 辅助函数:反转数组区间 [left, right]
void reverse(int R[], int left, int right) {
    while (left < right) {
        // 交换 R[left] 和 R[right]
        int temp = R[left];
        R[left] = R[right];
        R[right] = temp;
        left++;
        right--;
    }
}

// 主函数:循环左移 p 位
void leftShift(int R[], int n, int p) {
    // 处理 p >= n 的情况(题目保证 0<p<n,此步可省略但更健壮)
    p = p % n;  
    
    reverse(R, 0, p - 1);      // 反转前 p 个元素
    reverse(R, p, n - 1);      // 反转后 n-p 个元素
    reverse(R, 0, n - 1);      // 反转整个数组
}

3)复杂度分析

  • 时间复杂度:$ O(n) $
    (三次反转共遍历 $ \frac{p}{2} + \frac{n-p}{2} + \frac{n}{2} = n $ 次操作)

  • 空间复杂度:$ O(1) $
    (仅使用常数个辅助变量 temp, left, right

五 强相关知识点

5.1 就地逆转代码解释

代码
// 函数签名:接收数组 R,以及要反转的起始下标 left 和结束下标 right
void reverse(int R[], int left, int right) {
    
    // 循环条件:当左指针还在右指针左边时,继续交换
    // 一旦 left >= right,说明中间点已到达或交错,反转完成
    while (left < right) {
        
        // 1. 暂存左边的值(避免被覆盖丢失)
        int temp = R[left];
        
        // 2. 将右边的值赋给左边
        R[left] = R[right];
        
        // 3. 将暂存的值赋给右边(完成交换)
        R[right] = temp;
        
        // 4. 双指针向中间靠拢
        left++;   // 左指针右移
        right--;  // 右指针左移
    }
}
💡 核心逻辑图解

假设数组片段为 [A, B, C, D, E]left=0, right=4

  1. 第1轮:交换 AE[E, B, C, D, A],指针变为 13
  2. 第2轮:交换 BD[E, D, C, B, A],指针变为 22
  3. 终止left (2) < right (2) 不成立,循环结束。中间的 C 无需移动。
推广到“就地逆转” (In-place Reversal)

这个 reverse 函数是通用原语。任何“就地逆转”问题,本质上都是调用这个函数,只是调用的区间不同

🚀 应用场景一:整个数组逆序
  • 目标:将 $ [x_0, \ldots, x_{n-1}] $ 变为 $ [x_{n-1}, \ldots, x_0] $
  • 调用reverse(R, 0, n - 1);
  • 原理:直接翻转整个区间。

🚀 应用场景二:循环左移 p 位(本题解法)
  • 目标:$ AB \rightarrow BA $ ($ A $ 是前 $ p $ 个,$ B $ 是后 $ n-p $ 个)
  • 步骤
    1. reverse(R, 0, p - 1); // 逆序 A → $ A^r $
    2. reverse(R, p, n - 1); // 逆序 B → $ B^r $
    3. reverse(R, 0, n - 1); // 逆序整体 $ (A^r Br)r = BA $

🚀 应用场景三:循环右移 pp 位

  • 目标 A B → B A AB→BA ABBA(注意:右移 pp 位相当于把后 $ p $ 个移到前面)
    • 设 $ A $ 为前 n − p n−p np 个, $ B $ 为后 $ p $ 个。原序列 $ AB $,目标 $ BA $ 。
  • 步骤
    1. reverse(R, 0, n - p - 1); // 逆序 A
    2. reverse(R, n - p, n - 1); // 逆序 B
    3. reverse(R, 0, n - 1); // 逆序整体
🚀 应用场景四:单词翻转(句子逆序但单词内部顺序不变)
  • 输入"I am a student"

  • 目标"student a am I"

  • 步骤

    1. reverse(R, 0, len - 1);
      • 结果:"tneduts a ma I" (整个句子反了,单词也反了)
    2. 遍历数组,识别每个单词的起止位置 start, end
    3. 对每个单词再次调用 reverse(R, start, end);
      • "tneduts" →→ "student"
      • "a" →→ "a"
    • 最终结果:"student a am I"

六 扩展知识点

🔁 其他实现方法对比

方法时间复杂度空间复杂度优缺点
三次反转法$ O(n) $$ O(1) $✅ 最优解,408标准答案
辅助数组法$ O(n) $$ O(n) $❌ 空间不满足“尽可能高效”
逐个左移法$ O(n \times p) $$ O(1) $❌ 时间复杂度高( $ p $ 大时退化)
Juggling算法$ O(n) $$ O(1) $⚠️ 逻辑复杂,易错,非首选

💡 Juggling算法简介(了解即可)

  • 思想:将数组分为 gcd⁡(n,p)gcd(n,p) 个环,每个环内元素循环移动
  • 优点:理论最优,但实现复杂
  • 缺点:代码冗长,408不推荐(除非明确要求)

七 核心考点

  • 三次反转法思想

  • 原地 O(1) 空间

  • O(n) 时间

  • 算法题规范作答

八 408考研大纲和教材对应章节

资源章节核心内容
408考研大纲数据结构 → 线性表 → 数组掌握数组原地操作算法
严蔚敏《数据结构》第2章 2.3节“数组”数组基本操作与优化技巧

九 考点跟踪

年份题号考查内容CSDN 参考链接VX参考链接
2010第42题就地逆转408真题解析-2010-42-数据结构-数组循环左移
2011第42题顺序表
2012第42题顺序表

说明:本文内容基于公开资料整理,参考了包括但不限于《数据结构》(严蔚敏)、《计算机操作系统》(汤小丹)、《计算机网络》(谢希仁)、《计算机组成原理》(唐朔飞)等国内高校经典教材,以及其他国际权威著作。同时,借鉴了王道、天勤、启航等机构出版的计算机专业考研辅导系列丛书中的知识体系框架与典型题型分析思路。文中所有观点、例题解析及文字表述均为作者结合自身理解进行的归纳与重述,未直接复制任何出版物原文。内容仅用于学习交流,若有引用不当或疏漏之处,敬请指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

知行智研社

您的鼓励是我的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值