leetcode 189.旋转数组(C\C++\java\python)

PS:算法并非原创,仅作个人学习记录使用,侵删。

题目描述
在这里插入图片描述
算法分析
看到题目的初步算法思路是:
将数组转化为类链表结构,用一个指示下标的指针,向右移动k个(超过k就k%n)个元素大小,然后从当前指针为开始指针,得到结果。但是没办法做到原地算法。
还有一种思路也比较简单:截取,根据k将数组截取为两部分,然后互换,依然没办法做到原地算法。
还有一种不算是我的思路,算是我记得的一种算法:三次逆转,按照k将数组截取为前后两部分,两部分分别在原数组空间逆转,之后再将整个数组再次逆转,三次逆转之后将会得到正确结果。这种算是原地算法,而且很巧妙。
后来看了大佬们的实现思路,还有一种思路:原数组元素交换,这样也可做到原地算法,只是交换的过程较为复杂,详见C++代码实现和python代码实现的两种循环交换方式。

**代码实现
【C】

/*
C++采用的算法也就是截取的思路,将数组截取为两部分,交换顺序存入临时数组,之后再载入原数组
*/
void rotate(int* nums, int numsSize, int k){
    //nums为目标整型数组,numsSize表示数组长度,k表示移动幅度
	if(numsSize>k){//如果移动的步数没有超过数组长度,
		int *buf = (int *)malloc(numsSize*sizeof(int));//开辟新的存储空间
		memcpy(buf, nums+(numsSize-k),k*sizeof(int));//buf前半段,存储原数组中后半段长度为k的数组
		memcpy(buf+k,nums,(numsSize-k)*sizeof(int));//buf后半段,存储原数组中前半段长度为n-k的数组
		memcpy(nums, buf,numsSize*sizeof(int));//buf中的数据转存入nums中
	}
	else{
		k = k - numsSize;//相当于k %= numsSize。
		rotate(nums, numsSize, k);//递归采用rotate函数
	}
}

C语言参考网址
【C++】

/*
C++:循环交换
直接在原始数组上实现元素交换,不需要额外的存储空间,是一类原地算法。
将数组前后k个元素为一组进行交换,每次的前k个都不会重叠,每次的后k个基本上都是最后k个
*/
class Solution {
public:
    void swap(vector<int> & nums, int i, int j){//交换函数,交换nums中的元素i和元素j
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
    void rotate(vector<int>& nums, int k) {
        if(k>=nums.size())
            k%=nums.size();//控制实际的移动大小在一个数组长度范围内
        if(k!=0){//如果需要移动的话
            int n=nums.size();
            for (int start = 0; start < nums.size() && k != 0; n -= k, start += k,k %= n) {
                //start每次移动k步,在start和start+k之间的元素,需要和n-k和n之间的元素进行对应交换
                /*举例子:
                1 2 3 4 5 6 7 k=3
                第一次循环:start=0,替换nums[0]和nums[4],nums[1]和nums[5],nums[2]和nums[6],得到的数组是:5 6 7 4 1 2 3
                           ==>> n = 4, start = 3,k = 3( = 3%4)
                第二次循环:start=3,替换nums[3]和nums[4],nums[4]和nums[5],nums[5]和nums[6],得到的数组是:5 6 7 1 2 3 4
                           ==>> n = 1,start = 6,k = 0( = 3%1)
                由于k=0,结束循环
                */
                for (int i = 0; i < k; i++) {//每次分块对应交换
                    swap(nums, start + i, nums.size() - k + i);
                }
            }
        }
    }
};

C++参考网址
【java】

/*
java:三次逆转
将整体逆转,之后分组,两组元素分别进行逆转。是一个原地算法
需要自定义逆转的算法函数
*/

class Solution {
    public void rotate(int[] nums, int k) {
        k %= nums.length;//缩小移动步数
        //先整体后部分
        reverse(nums, 0, nums.length - 1);//逆转整体
        reverse(nums, 0, k - 1);//逆转前半段
        reverse(nums, k, nums.length - 1);//逆转后半段
        //如果先部分后整体的话,分段就是0~nums.length-k-1,num.lenght-k~num.lenght-1
    }
    public void reverse(int[] nums, int i, int j){//逆转nums[i]~nums[j]的元素
        while(i < j){//首尾交换
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            i++;
            j--;
        }
    }
}

java参考网址
【python】**

#
# python:循环交换
# 基本思想和C++的差不多,也是一类原地算法,但是由于是单个元素之间的比较,有些复杂
#
class Solution:
    def rotate(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: void Do not return anything, modify nums in-place instead.
        """
        if k == 0 or len(nums) < 2:#不需要移动的情况
            return
        length = len(nums)#length表示数组长度
        n, i, j = 0, 0, 0
        temp1 = nums[0]#起始元素值
        while n < length:#循环数组
            #依然是循环交换的策略,不同的是:这里是单个元素之间的交换,而C++展示的是带着分块思想的整体交换
            j = (j + k) % length
            temp2 = nums[j]
            nums[j] = temp1
            temp1 = temp2
            if i == j:
                i = (i + 1) % length
                j = i
                temp1 = nums[i]
            n += 1

python参考网址

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值