leetcode之189旋转数组Golang

题目描述

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

示例 1:

输入: [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:

输入: [-1,-100,3,99] 和 k = 2
输出: [3,99,-1,-100]
解释:
向右旋转 1 步: [99,-1,-100,3]
向右旋转 2 步: [3,99,-1,-100]

说明:

  • 尽可能想出更多的解决方案,至少有三种不同的方法可以解决这个问题。

  • 要求使用空间复杂度为 O(1) 的 原地 算法。

 

题解

先决知识

定义一个数N的加法域,例如5的加法域,那么它包含的元素就是{0,1,2,3,4}

定义加法:设p是域中一个元素,有其他数k,那么加法为p2=p+k,有如下结论:

  • 如果N和k互素,那么域中任何一个元素都是这个域的加法生成元

  • 如果N和K不互素,并且最大公约数为C,那么N的这个加法域可以分为N/C个部分,分别为一个子域,并且子域中任意元素都是该子域的加法生成元

算法

首先求数组长度length和k的最大公约数:

  • 如果公约数为1,那么说明了他们互素,由前面先决知识可知,数组中任意元素都是一个生成元,可以由任意数通过这个加法遍历到数组中所有元素

    • 设置一个循环,循环的次数为数组的长度,从数组任意位置开始,然后每次执行的操作是将上一个数挪动到它最终应该待的地方,然后将目标位置的数存到一个临时变量中

    • 继续下一次循环,将临时变量中的元素存储到它最终应该待的位置,将目标位置的元素存储到临时变量

    • 重复上述循环可以遍历完整个数组

  • 如果最大公约数不为1,说明了他们不是互素的,由先决条件可知,我们需要将他们分为N/C个子域,然后对每个子域执行互素时的操作

    • 易得,数组中连续C个元素是分别属于C个子域的元素,由这C个元素可以通过加法遍历到整个数组

 

代码

func rotate(nums []int, k int) {
    length := len(nums)
    k %= length
    if k == 0 {
        return
    }
    // 此时求length和k的最大公约数
    dividend, comDivisor := length, k
    for {
        tmpDividend, tmpDivisor := comDivisor, dividend%comDivisor
        if tmpDivisor == 0 {
            break
        }
        dividend, comDivisor = tmpDividend, tmpDivisor
    }
    var times, elemNum int
    // 重启循环的次数
    if comDivisor == 1 {
        times, elemNum = 1, length
    } else {
        times, elemNum = comDivisor, length/comDivisor
    }
    for i := 0; i < times; i++ {
        index := i
        tmp := nums[length-k+i]
        for j := 0; j < elemNum; j++ {
            tmp, nums[index], index = nums[index], tmp, (index+k)%length
        }
    }
}

  

 

tips

今天写代码犯了一个错,我还在想为什么我向函数传的是数组,也就是传的是数组的指针(地址),为什么修改了数组的值,在外层函数中没有效果,我的代码如下:

package main
​
import (
    "fmt"
)
​
func main() {
    a := []int{2, 3, 4}
    test(a)
    fmt.Println(a)
    test2(a)
    fmt.Println(a)
}
​
func test(a []int) {
    b := []int{1, 2, 3}
    // a只是一个标识符,这里a已经指向了另一个内存地址了,所以这个a已经不是外层函数的那个a了
    a = b
}
​
func test2(a []int) {
    // a仍然是一个标识符,但是a和外层函数的a指向的是同一个内存地址,所以此时在函数内部修改数组元素是有效的
    a[0] = 5
}

  

 

posted @ 2020-09-13 22:14  胖胖咩  阅读(226)  评论(0)    收藏  举报