189.轮转数组

题目:

给定一个整数数组 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

进阶:

  • 尽可能想出更多的解决方案,至少有 三种 不同的方法可以解决这个问题。
  • 你可以使用空间复杂度为 O(1) 的 原地 算法解决这个问题吗?

解题思路:

 方法一:记录被移位出去的数据,将移位后的数据放到数据起始部分,注意移位的长度要对nums的长度取余,循环移位不影响结果

代码:
length = len(nums)
        k = k%length
        if k==0:
            return nums
        right = length-1
        outputs = []
        for i in range(length-k, right+1):
            outputs.append(nums[i])
        while right>k-1:
            nums[right] = nums[right-k]
            right-=1
        for i in range(len(outputs)-1, -1, -1):
            nums[i] = outputs[i]
        return nums

方法二:选择用指针,使用循环指针进行记录,将指针遍历的数据传回原nums数组

代码:
class Node:
    def __init__(self, x):
        self.val = x
        self.next = None

def create(arr):
    if not arr:
        return None
    head= Node(arr[0])
    current = head
    for value in arr[1:]:
        current.next = Node(value)
        current = current.next
    current.next = head
    # 定义一个循环指针
    return head

def list_to_array(head):
    if not head:
        return []
    p = head
    arr = []
    while True:
        arr.append(p.val) 
        p = p.next
        if p == head:
            break
    return arr

class Solution:
    def rotate(self, nums, k: int) -> None:
        k = k%len(nums)
        if k==0:
            return nums
        head = create(nums)
        for i in range(len(nums)-k):
            head = head.next
        nums[:] = list_to_array(head)

方法三:使用python的切片操作

代码:
class Solution:
    def rotate(self, nums, k: int) -> None:
        k = k%len(nums)
        if k==0:
            return nums
        nums[:] = nums[-k:]+nums[:-k]

方法四:环状替换

对于n个长度的数组,向右移位k次,需要先对k取余,因为移位n的倍数次不会影响原数组的位置。

start从0开始,向右移位k次相当于将start移动到(start+k)%n的位置上,这并不是一个交换的操作,而是将数值直接进行移位操作,将(start+k)%n的值赋予到temp上用于后续移位操作。那么(start+k)%n的数值会继续移位到(start+2*k)%n的位置上依次类推。

假设替换结束一共经历了a次,一共移动b个元素,那么可以得到结论an = bk,这里是因为通过判断是否回到原点来结束一轮的遍历,一共移动b个元素,每次中间间隔k步,所以一共经历了bk个元素,而总共循环了a次数组,长度为an。让a尽可能小那么an就是n和k的最小公倍数a = lcm(n, k),每轮遍历lcm(n, k)/k个元素,而这些元素不会重复,所以要遍历所有元素需要的次数就是n/lcm(n,k)/k,也就是n*k/lcm(n,k) = gcd(n,k)

代码:
length = len(nums)
        k = k%length
        if k==0:
            return nums
        count = math.gcd(length, k)
        for start in range(count):
            current = start
            temp = nums[start]
            q = 0
            while True:
                next = (k+current)%length
                q = nums[next]
                nums[next] = temp
                temp = q
                current = next
                if current==start:
                    break

你可能感兴趣的:(LeetCode-热题100,LeetCode-数组,LeetCode-指针,算法,数据结构,leetcode)