数组轮转的三步反转算法


1、题目

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

下面是一个示例:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]

力扣链接


2、思路

图解如下:

观察发现,轮转后的数组与原数组相比有一部分元素移动至数组头部,有一部分元素移动至数组尾部。因此考虑先反转数组,然后反转数组前段,最后反转数组后段。

注意: k可能大于等于数组长度,应该确保k<=数组长度,避免出现访问越界。

分三步反转:

  1. 反转整个数组

  2. 反转前k个元素

  3. 反转后n-k个元素

代码实现

//反转函数
void reverse(int* nums, int left, int right)
{
    while(left < right)
    {
        //反转左右指针指向的元素
        int tmp = nums[left];
        nums[left++] = nums[right];
        nums[right--] = tmp;
    }
}

void rotate(int* nums, int numsSize, int k)
{
    //k大于元素个数,应当减小n倍元素个数,因为反转元素个数个位置,顺序和原数组一样,相当于没反转
    //k大于数组长度的极端情况
    k %= numsSize; 

    //三段反转
    //反转数组整体
    reverse(nums, 0, numsSize-1);
    //反转轮转部分
    reverse(nums, 0, k-1);
    //反转非轮转部分
    reverse(nums, k, numsSize-1); 
}

3、复杂度

时间复杂度:N是数组长度

  • 反转数组整体,遍历一次数组为O(N)
  • 反转轮转部分,遍历k个元素为O(1)
  • 反转非轮转部分,遍历n-k个元素为O(N)

所以整个时间复杂度为O(N)。

空间复杂度:在原数组的空间上,仅交换数组内元素,没有申请额外的空间,空间复杂度为O(1)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
时间片轮转算法是一种基于时间片的调度算法,其主要思想是将所有就绪队列中的进程按照一定的时间片轮流使用CPU。以下是用C语言实现时间片轮转算法的代码,利用结构体数组实现: ```c #include <stdio.h> #include <stdlib.h> // 进程结构体 typedef struct { int pid; // 进程ID int burst_time; // 需要执行的时间 int remaining_time; // 剩余需要执行的时间 int arrival_time; // 到达时间 int waiting_time; // 等待时间 int turnaround_time; // 周转时间 } Process; // 就绪队列 typedef struct { Process *process; // 进程指针 int front; // 队首指针 int rear; // 队尾指针 } ReadyQueue; // 初始化就绪队列 void initReadyQueue(ReadyQueue *queue, int n) { queue->process = (Process*)malloc(n * sizeof(Process)); queue->front = 0; queue->rear = -1; } // 判断队列是否为空 int isQueueEmpty(ReadyQueue *queue) { return queue->rear < queue->front; } // 将进程加入就绪队列 void enqueue(ReadyQueue *queue, Process process) { queue->rear++; queue->process[queue->rear] = process; } // 从就绪队列中取出进程 Process dequeue(ReadyQueue *queue) { Process process = queue->process[queue->front]; queue->front++; return process; } // 时间片轮转调度算法 void roundRobinScheduling(Process *processes, int n, int time_slice) { // 初始化就绪队列 ReadyQueue readyQueue; initReadyQueue(&readyQueue, n); int current_time = 0; // 当前时间 int finished_count = 0; // 完成的进程数 int i; // 将所有进程加入就绪队列 for (i = 0; i < n; i++) { enqueue(&readyQueue, processes[i]); } // 不断循环,直到所有进程都执行完毕 while (finished_count < n) { // 从就绪队列中取出一个进程 Process current_process = dequeue(&readyQueue); // 如果该进程还需要执行 if (current_process.remaining_time > 0) { // 计算该进程的执行时间 int execute_time = time_slice; if (current_process.remaining_time < execute_time) { execute_time = current_process.remaining_time; } // 更新当前时间和该进程的剩余需要执行的时间 current_time += execute_time; current_process.remaining_time -= execute_time; // 将该进程重新加入就绪队列 enqueue(&readyQueue, current_process); } else { // 如果该进程已经执行完毕,更新其周转时间和等待时间 current_process.turnaround_time = current_time - current_process.arrival_time; current_process.waiting_time = current_process.turnaround_time - current_process.burst_time; // 输出该进程的信息 printf("Process %d: waiting time = %d, turnaround time = %d\n", current_process.pid, current_process.waiting_time, current_process.turnaround_time); finished_count++; } } } int main() { int n, time_slice, i; printf("Enter the number of processes: "); scanf("%d", &n); // 动态申请进程数组的空间 Process *processes = (Process*)malloc(n * sizeof(Process)); // 输入每个进程的信息 for (i = 0; i < n; i++) { printf("Enter the burst time of process %d: ", i); scanf("%d", &processes[i].burst_time); processes[i].remaining_time = processes[i].burst_time; processes[i].pid = i; processes[i].arrival_time = 0; processes[i].waiting_time = 0; processes[i].turnaround_time = 0; } printf("Enter the time slice: "); scanf("%d", &time_slice); // 执行时间片轮转调度算法 roundRobinScheduling(processes, n, time_slice); // 释放进程数组的空间 free(processes); return 0; } ``` 在这个程序中,我们首先定义了一个`Process`结构体,用于存储每个进程的信息,包括进程ID、需要执行的时间、剩余需要执行的时间、到达时间、等待时间和周转时间。然后我们定义了一个`ReadyQueue`结构体,用于存储就绪队列的信息,包括进程指针、队首指针和队尾指针。 接下来,我们实现了一些操作就绪队列的函数,包括初始化就绪队列、判断队列是否为空、将进程加入就绪队列和从就绪队列中取出进程。在`roundRobinScheduling()`函数中,我们首先初始化就绪队列,并将所有进程加入就绪队列。然后我们开始循环,直到所有进程都执行完毕。在每次循环中,我们从就绪队列中取出一个进程,判断该进程是否还需要执行。如果需要执行,则计算该进程的执行时间,并更新当前时间和该进程的剩余需要执行的时间,然后将该进程重新加入就绪队列。如果该进程已经执行完毕,则更新其周转时间和等待时间,并输出该进程的信息。最后,我们释放进程数组的空间,程序结束。 注意:这段代码中的时间片长度是固定的,实际应用中可能需要根据不同的进程动态调整时间片长度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值