LeetCode #189.轮转数组

力扣 | 189.轮转数组

题目截图

方法一:三次反转

当每当k等于n倍速,完成一整个循环,相当于没有变化。

利用k=k%n,去除无效变化的部分。

将整个数组分为前后两部分,三次反转后得到最后的结果。

例如:nums=[1, 2, 3, 4, 5, 6, 7]

k = 3

则分为[1, 2, 3, 4]和[5, 6, 7]两段。

第一次反转第一段,得[4, 3, 2, 1, 5, 6, 7]。

第二次反转第二段,得[4, 3, 2, 1, 7, 6, 5]。

第三次全部反转,得[5, 6, 7, 1, 2, 3, 4]。

复杂度

时间复杂度O(n)

空间复杂度O(1)

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        def swap(l, r):
            while(l<r):
                nums[l], nums[r] = nums[r], nums[l]
                l += 1
                r -= 1
        swap(0, n-1-k)
        swap(n-k, n-1)
        swap(0, n-1)

完整测试代码

from typing import List

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        n = len(nums)
        k %= n
        def swap(l, r):
            while(l<r):
                nums[l], nums[r] = nums[r], nums[l]
                l += 1
                r -= 1
        swap(0, n-1-k)
        swap(n-k, n-1)
        swap(0, n-1)


class main:
    a = Solution()
    nums = [-5, -4, -3, -2, -1]
    k = 3
    a.rotate(nums,k)
    print(nums)


if __name__ == '__main__':
    main()

 借助python的切片完成反转

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        nums[:] = nums[::-1]
        nums[:k] = nums[:k][::-1]
        nums[k:] = nums[k:][::-1]

 

方法二:直接用python切片

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        nums[:] = nums[n-k:] + nums[:n-k]

方法三:直接创建新数组

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        ans=[0]*n
        for i in range(0, n):
            ans[(i+k)%n] = nums[i]
        for i in range(0, n):
            nums[i] = ans[i]

方法四:环状替代

位置 0 的元素会放至 (0+k)mod n 处,反复这样移动就会形成一个移动闭环。

当然,这样并不能完全遍历每个元素,所以这样环状移动完成,回到最开始的位置后,就往下移动一个元素,然后再开始这样的环状移动。

何时能遍历完全部元素呢?

元素个数n和移动步长k的最大公约数就是环状移动的个数。

移动总步数=环状移动个数*环内移动步数

所以设置内外两个循环。

外层循环次数为最大公约数,内层循环移动替代,当替换回到开始的位置就退出内层循环。

import math

class Solution:
    def rotate(self, nums: List[int], k: int) -> None:
        n = len(nums)
        k %= n
        count = math.gcd(k, n)
        for start in range(0, count):
            current = start
            prev = nums[start]
            while True:
                next = (current + k) % n
                nums[next], prev = prev, nums[next]
                current = next
                if next == start:
                    break

扩展:自定义最大公约数

辗转相除法

    def my_gcd(x, y):
        while x%y:
            x, y = y, x%y
        return y

迭代

    def my_gcd(x, y):
        return x if y==0 else self.my_gcd(x, x%y)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值