LeeCode刷题记录—轮转数组
在做了两道题之后,我逐渐适应了LeeCode题目的难度,并可以写出正确答案了。
我发现在这些简单的问题里面,其他大部分算法的时间和空间差别不大,我需要学会的是怎么在设计时优化自己的算法,什么样的算法是耗时的,什么样的算法是不耗时的。
上面是一些心得,下面是题目:
给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。
这是我看到这题时的一开始的思路和我的代码:(这个思路主要是参考了昨天的数组的平方的算法)
class Solution {
public:
void rotate(vector<int>& nums, int k) {
int point;int n = nums.size();
vector<int> num(n);
for(int i = 0;i < n;++i){
num[(i + k) % n] = nums[i];
}
nums= num;//不知道为什么num的值无法返回,这个我们C语言还没教。我只能用等号了
}
};
从这个图不难看出,我的算法使用了两个数组的空间,却只输出了一个数组,以及我一开始的想法是有点耗时的。
因为我一开始的想法把这个数组分成了两半,一半是k前的,一半是k后的,实际写程序的过程中我发现我不得不写一个if来补上k前的元素,在循环里面加上一个判断毫无疑问是费时的。
所以我就在纸上寻找i和k的关系,找到一个不需要用if判断的公式来输出第二个数组。
num[(i + k) % n] = nums[i];//注释在这里
当i+k等于数组的长度n时,将i位置上的元素作为新数组的第一个元素。
以这个思路为起点,我发现当(i+1+k)% n的余数刚好是1,在i+k<2n之前,余数其实1,2,3,4......n。
接着官方提供了一种相比于nums = num;
更快的运行方式,用下面这行代码直接替代:
nums.assign(num.begin(), num.end());
我在CSDN上查了一下,assign可以将来源对象复制到目标对象,用了这行代码后我的算法从32ms运行到了20ms,以及4ms的算法和20ms的算法一模一样。
说会空间的问题,我的算法的空间复杂度是O(n),官方提供了一种利用双指针的空间复杂度为O(1)的方法,时间复杂度相同:
class Solution {
public:
void reverse(vector<int>& nums, int start, int end) {//这个函数和题目无关,是要自己编写的,函数的作用是将范围内的元素翻转
while (start < end) {//当左指针小于右指针时
swap(nums[start], nums[end]);//用于交换两个元素的值,用官方的说法就是翻转元素
start += 1;//左指针右移一格
end -= 1;//右指针左移一格
}//退出while循环时,范围内的所有元素已经完成了翻转
}
void rotate(vector<int>& nums, int k) {//这是题目里面一开始就写好了的
k %= nums.size();//k赋值为k%nums.size()的模(余数),这个值就代表了k的位置
//reverse能够将范围内的元素颠倒顺序放置
reverse(nums, 0, nums.size() - 1);//翻转数组内的所有元素
//假设一开始的顺序是a,b,c,d,f,g 现在就是g,f,d,c,b,a
reverse(nums, 0, k - 1);//把数组第一个元素到k位置的元素的排序恢复正常
//假设k是2,现在就是f,g,d,c,b,a 可以注意到f到g已经恢复原来的顺序排列了
reverse(nums, k, nums.size() - 1);//接下来再把k+1的位置上的元素到数组内的最后一个元素的排序恢复正常,从f,g,d,c,b,a变成了f,g,a,b,c,d。完成输出
}
};
作者:力扣官方题解
链接:https://leetcode.cn/problems/rotate-array/solutions/551039/xuan-zhuan-shu-zu-by-leetcode-solution-nipk/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。