189. 轮转数组(C++)
题目
给定一个整数数组 nums
,将数组中的元素向右轮转 k
个位置,其中 k
是非负数。
示例 1:
输入: 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:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]
解释:
向右轮转 1 步: [99,-1,-100,3]
向右轮转 2 步: [3,99,-1,-100]
提示:
1 <= nums.length <= 105
-231 <= nums[i] <= 231 - 1
0 <= k <= 105
题解
void rotate(std::vector<int>& nums, int k) {
int n = nums.size();
k = k % n; // 如果k大于n,取模以避免不必要的旋转
// 第一步:反转整个数组
std::reverse(nums.begin(), nums.end());
// 第二步:反转前k个元素
std::reverse(nums.begin(), nums.begin() + k);
// 第三步:反转剩下的元素
std::reverse(nums.begin() + k, nums.end());
}
算法原理
这个算法利用了数组反转(reversal)的性质来实现向右轮转。核心思想是将整个数组分为几个部分,并通过反转这些部分来达到轮转的效果,而不是逐个移动元素。
步骤分解
- 计算有效的k值:
由于k可能大于数组的长度n,直接按k进行轮转可能会导致不必要的操作。因此,我们首先计算k = k % n
,确保k是小于n的非负整数。这样,我们就得到了一个“有效”的k值,它代表了实际需要轮转的步数。 - 反转整个数组:
接下来,我们反转整个数组。这一步的目的是将原本在数组末尾的元素移动到数组的开始位置,这是轮转操作的一部分。 - 反转前k个元素:
在第一步反转整个数组后,原本位于数组末尾的k个元素现在位于数组的开头。但是,这些元素可能并不是我们想要的顺序(即,它们可能不是原数组中连续的元素)。因此,我们需要将这k个元素再次反转,以恢复它们在原数组中的相对顺序(但位置已经移动到了开头)。 - 反转剩余的元素:
最后,除了前k个元素之外,数组中的其他元素也需要进行反转。这是因为,在第一步反转整个数组后,这些元素的顺序被打乱了。通过反转这些元素,我们可以恢复它们在原数组中的顺序(尽管它们现在位于数组的末尾部分)。
为什么这种方法有效?
这种方法之所以有效,是因为通过反转操作,我们实际上是在重新排列数组中的元素,而不是逐个移动它们。这种方法避免了逐个移动元素所带来的高昂时间成本(特别是对于大型数组)。
具体来说,通过三次反转操作,我们实际上是在做以下事情:
- 将数组末尾的元素“移动到”开头(第一次反转)。
- 将这些移动到开头的元素“排序”成它们在原数组中的顺序(第二次反转)。
- 将剩余的元素“排序”成它们在原数组中的顺序(第三次反转)。
- 最终,我们得到了一个向右轮转了k个位置的数组,而且这个过程是高效的,时间复杂度为O(n)。
原文地址:https://blog.csdn.net/weixin_45813121/article/details/142516888
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!