刷题使我快乐,满脸开心.jpg

  • 来源:力扣(LeetCode)
  • 链接:https://leetcode.cn/problems/rotate-array/
  • 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目

给定一个整数数组 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 <= 10^5
  • -2^31 <= nums[i] <= 2^31 - 1
  • 0 <= k <= 10^5

进阶:

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

思路

额外数组

这个思路很简单,空间复杂度高一些记录下就好了

循环交替

这个思路就是不断往后交换,直接把数字摆到它应该在的位置,会有几个注意点:

  • 用额外变量存下来下一个数字,便于持续往后计算
  • 记录初始点,用是否回到初始点决定是否需要往右移动一位继续往后交换
  • 记录总共摆放的次数,因为没有限制,会一直往后交换下去,其实我们简单画一下就明白,有可能交换回初始点时,很多位置就已经完成了,初始点右移是有可能把已经摆好位置的数字移动到错误位置,所以要限制总计交换次数

翻转数组

一图胜千言

大体思路就是这样了,上代码~

代码

交替

func rotate(nums []int, k int) {
	// 整除就直接return
	if k%len(nums) == 0 {
		return
	}
	p := 0
	// 把k取余,最多需要这么多起始点就够了
	k = k % len(nums)
    // 记录起始点
	startP := 0
    // 计算要摆放位置
	nextP := 0
    // 缓存下个要摆放的数字
	back := 0
    // 总计移动次数
	count := 0
    // 摆够了就不用继续了
	for startP < k && count < len(nums) {
		p = startP
		back = nums[p]
		for count < len(nums) {
            // 计算下个摆放位置
			nextP = (p + k) % len(nums)
            // 存下个摆放数字
			back, nums[nextP] = nums[nextP], back
            // 步进
			p = nextP
            // 统计摆放次数
			count++
            // 回到起始点就换个起始点
			if p == startP {
				break
			}
		}
        // 步进起始点
		startP++
	}
}

翻转

func reverse(a []int) {
	for i, j := 0, len(a)-1; i < j; i, j = i+1, j-1 {
		a[i], a[j] = a[j], a[i]
	}
}

func rotate(nums []int, k int) {
    // 计算旋转点
	n := k % len(nums)
    // 全量翻转
	reverse(nums)
    // 分别部分翻转
	reverse(nums[:n])
	reverse(nums[n:])
}