数组元素通过单个移动移动了k个位置?

1. 问题描述

本文所述问题是指将一个长度为n的数组中的元素向右移动k个位置,其中k是非负整数。例如,给定数组 nums = [1,2,3,4,5,6,7]k = 3,将数组向右移动3个位置后得到 [5,6,7,1,2,3,4]

2. 解法分析

2.1 暴力法

暴力法是最直观的方法之一,通过多次交换相邻元素的位置来实现循环移位。具体的方法是,将数组中的最后一个元素与倒数第二个元素交换位置,然后将倒数第二个元素与倒数第三个元素交换位置,以此类推,直到将第一个元素与最后一个元素交换k次,即可实现循环移位。时间复杂度为 O(kn)

void rotate(vector<int>& nums, int k) {

int n = nums.size();

k = k % n;

for (int i = 0; i < k; i++) {

int temp = nums[n - 1];

for (int j = n - 1; j > 0; j--) {

nums[j] = nums[j - 1];

}

nums[0] = temp;

}

}

2.2 环状替换

环状替换是一种更加高效的方法,我们观察移动后的数组可以发现,每个元素都是移动的k个位置以后才到达终点的,而且多个元素可能会到达同一个位置,因此可以将这些元素看作是一个循环的"环",并将每个元素在这个"环"上移动,从而实现整个数组的循环移位。具体的做法是,从第一个元素开始,将其向右移动k个位置后到达的位置上的元素保存下来,并将该位置上的元素向右移动k个位置,直到回到第一个元素,这样一个"环"就完成了移动。然后再从未移动的下一个位置开始,重复上述过程,直到所有元素都移动完毕。时间复杂度为 O(n)

void rotate(vector<int>& nums, int k) {

int n = nums.size();

k = k % n;

int count = 0;

for (int start = 0; count < n; start++) {

int current = start;

int prev = nums[start];

do {

int next = (current + k) % n;

int temp = nums[next];

nums[next] = prev;

prev = temp;

current = next;

count++;

} while (start != current);

}

}

2.3 数组翻转

数组翻转是一种更加简单的方法,通过反转数组中的前k个元素,后n-k个元素,以及整个数组,即可实现循环移位。具体的做法是,先将前k个元素翻转,再将后n-k个元素翻转,最后将整个数组翻转。时间复杂度为 O(n)

void reverse(vector<int>& nums, int left, int right) {

while (left < right) {

swap(nums[left], nums[right]);

left++;

right--;

}

}

void rotate(vector<int>& nums, int k) {

int n = nums.size();

k = k % n;

reverse(nums, 0, n - 1);

reverse(nums, 0, k - 1);

reverse(nums, k, n - 1);

}

3. 总结

本文介绍了三种不同的方法来实现循环移位,包括暴力法、环状替换和数组翻转。这三种方法的时间复杂度分别为 O(kn)O(n)O(n),其中环状替换和数组翻转的时间复杂度较低,因此推荐使用这两种方法来实现循环移位。同时,需要注意数组下标的边界问题以及循环次数的计算方法,以避免出现错误。

后端开发标签