【问题标题】:Rotate Array in Go在 Go 中旋转数组
【发布时间】:2018-06-13 09:25:42
【问题描述】:

这是一个 LeetCode 问题:189. Rotate Array:

给定一个数组,将数组向右旋转 k 步,其中 k 为 非负数。

示例 1:

输入:[1,2,3,4,5,6,7] 和 k = 3
输出:[5,6,7,1,2,3,4]

这是我的解决方案:

func rotate(nums []int, k int)  {
    k = k % len(nums)
    nums = append(nums[k:],nums[0:k]...)
    fmt.Println(nums)
}

这是一个简单的算法,但它不起作用。

我是 Go 新手。我想nums 是按值传递的,对nums 的更改不会影响真正的nums

我怎样才能做到这一点?

【问题讨论】:

  • 您必须返回数字。在博客中了解切片在 Go 中的工作原理。
  • slice 已经指向一个数组,所以不需要单独指向它们。正如@Volker 建议的那样,您应该在修改相同的切片后返回您的切片

标签: go slice


【解决方案1】:

这是一种旋转浮点 32 切片的方法,您可以将其更改为其他类型。

//RotateF32Slice positive n rotate to the left, negative to right
func RotateF32Slice(slice []float32, n int) (rotateSlice []float32) {
    var begin []float32
    var end []float32
    size := len(slice)
    rotateSlice = make([]float32, size)

    nAbs := math.Abs(float64(n))

    if int(nAbs) > size {
        remainder, _ := QuotientAndRemainderF32(float32(n), float32(size))
        n = int(remainder)
    }

    if n != 0 {
        if n > 0 {
            index := size - n
            begin = slice[index:]
            end = slice[0:index]
            copy(rotateSlice, begin)
            copy(rotateSlice[n:], end)
        } else {
            n = int(nAbs)
            index := size - n
            begin = slice[n:]
            end = slice[0:n]
            copy(rotateSlice, begin)
            copy(rotateSlice[index:], end)
        }
    } else {
        copy(rotateSlice, slice)
    }

    return rotateSlice
}

//QuotientAndRemainderF32 Computes the integer quotient and the remainder of the inputs. This function rounds floor(x/y) to the nearest integer towards -inf.
func QuotientAndRemainderF32(x, y float32) (Remainder, Quotient float32) {
    Quotient = float32(math.Floor(float64(x / y)))
    Remainder = x - y*Quotient
    return Remainder, Quotient
}

【讨论】:

    【解决方案2】:

    这不起作用,因为[]byte 是一个类似于“指向数组的指针”的切片。正在做:

    func f(v []T) {
      v = ... //
    }
    

    不会对调用者产生任何明显的影响。假设您的 append 方式是正确的(没有真正检查过),您可以这样做:

    func rotate(nums []int, k int) {
        k = k % len(nums)
        temp := append(nums[k:], nums[0:k]...)
        copy(nums, temp) // this actually writes to where nums points to
    }
    
    func main() {
        nums := []int{1,2,3,4,5,6,7}
        rotate(nums ,3)
        fmt.Println(nums)
    }
    

    【讨论】:

      【解决方案3】:

      在 Go 中,所有参数都按值传递。

      Go 切片在运行时由切片描述符表示:

      type slice struct {
          array unsafe.Pointer
          len   int
          cap   int
      }
      

      如果您更改函数中的任何切片描述符值,则传达更改,通常通过返回更改后的切片描述符。


      您的 rotate 函数将切片 num 指针的值更改为基础数组和切片容量,因此返回 num

      例如,在我修复了您的rotate 算法中的错误之后,

      package main
      
      import "fmt"
      
      func rotate(nums []int, k int) []int {
          if k < 0 || len(nums) == 0 {
              return nums
          }
      
          fmt.Printf("nums %p array %p len %d cap %d slice %v\n", &nums, &nums[0], len(nums), cap(nums), nums)
      
          r := len(nums) - k%len(nums)
          nums = append(nums[r:], nums[:r]...)
      
          fmt.Printf("nums %p array %p len %d cap %d slice %v\n", &nums, &nums[0], len(nums), cap(nums), nums)
      
          return nums
      }
      
      func main() {
          nums := []int{1, 2, 3, 4, 5, 6, 7}
      
          fmt.Printf("nums %p array %p len %d cap %d slice %v\n", &nums, &nums[0], len(nums), cap(nums), nums)
      
          nums = rotate(nums, 3)
      
          fmt.Printf("nums %p array %p len %d cap %d slice %v\n", &nums, &nums[0], len(nums), cap(nums), nums)
      }
      

      输出:

      nums 0xc00000a080 array 0xc00001a1c0 len 7 cap 7 slice [1 2 3 4 5 6 7]
      nums 0xc00000a0c0 array 0xc00001a1c0 len 7 cap 7 slice [1 2 3 4 5 6 7]
      nums 0xc00000a0c0 array 0xc00001a240 len 7 cap 8 slice [5 6 7 1 2 3 4]
      nums 0xc00000a080 array 0xc00001a240 len 7 cap 8 slice [5 6 7 1 2 3 4]
      

      参考:The Go Blog: Go Slices: usage and internals

      【讨论】:

        【解决方案4】:

        解决方案

        解决方案 1:

        func rotate(ar []int,d,n int) []int{
            var newArray []int
            for i:=0;i<d;i++{
                newArray = ar[1:n]
                newArray = append(newArray,ar[0])
                ar = newArray
            }
        
            return ar
        }
        

        解决方案 2:

        func rotateR(ar []int,d,n int) []int{
            ar = append(ar[d:n],ar[0:d]...)
            return  ar
        }
        

        【讨论】:

          【解决方案5】:
          func rotate(nums []int, k int) {
              k = k % len(nums)
              result := append(nums[len(nums)-k:], nums[:len(nums)-k]...)
              for i := 0; i < len(nums); i++ {
                  nums[i] = result[i]
              }
          }
          

          【讨论】:

            【解决方案6】:

            当我在阅读“Go 编程语言”一书时遇到这个问题时才回答这个问题。它提出了一个非常优雅的算法来使用 reverse 函数并将其应用三次以实现 k elems 所需的旋转。像这样的

            // function to rotate array by k elems (3 reverse method)
            func rotate(arr []int, k int) {
                reverse(arr[:k])
                reverse(arr[k:])
                reverse(arr)
            }
            

            请注意,您必须编写一个反向函数。 Go 没有提供一个。这是一个 O(n) 解,占用 O(1) 空间。

            【讨论】:

              【解决方案7】:

              这是我对同一个hackerrank problem的解决方案

              func rotateLeft(d int32, arr []int32) []int32 {
                  for ; d > 0 ; d-- {
                      left := arr[0]
                      arr = arr[1:]
                      arr = append(arr, left)        
                  }
                  return arr
              }
              

              【讨论】:

                【解决方案8】:

                对我来说,这适用于许多数组旋转,但不适用于数百个 nums[]。

                func rotate(nums []int, k int)  {
                    for count:=k; count>0; count--{
                        if len(nums) >= 1 && len(nums) <= 10^5 {
                            for i:=len(nums)-1; i>0; i--{
                                nums[i], nums[i-1] = nums[i-1], nums[i]
                            }
                        }
                    }
                }
                

                【讨论】:

                  【解决方案9】:

                  给定一个数组,将数组向右旋转 k 步,其中 k 为 非负数。

                  示例 1:

                  输入:[1,2,3,4,5,6,7] 和 k = 3 输出:[5,6,7,1,2,3,4] 块引用

                  首先,对于 k=3,不应该是输出 [4,5,6,7,1,2,3] 吗?

                  对于大多数数组操作,向新创建的数组添加元素总是比更改源数组更简单。如果数组不是很大(占用 Gigs 内存 / 数十亿个项目等),您可以使用一个函数按您需要的顺序将元素添加到新创建的数组并返回新的:

                  // GO 1.18
                  func rot[T any](slice []T, k int) (newSlice []T){
                      l := len(slice)
                      for i := range slice {
                          newSlice = append(newSlice, slice[(k+i) % l])
                      }
                      return
                  }
                  
                  fmt.Printf("Slice %v after rotation %v\n", []int{1,2,3,4,5,6,7}, rot[int]([]int{1,2,3,4,5,6,7}, 3))
                  //Slice [1 2 3 4 5 6 7] after rotation [4 5 6 7 1 2 3]
                  
                  

                  如果你坚持使用“切片”,代码如下:

                  func rotationBySlicing[T any](slice []T, k  int) (newSlice []T) {
                      if len(slice) == 0 {
                          return slice
                      }
                      return append(slice[(k%len(slice)):],slice[0:k%len(slice)]...)
                  }
                  
                  
                  fmt.Printf("Array %v after rotation %v\n", []string{}, rotationBySlicing[string]([]string{},1))
                      fmt.Printf("Array %v after rotation %v\n", []string{"a"}, rotationBySlicing[string]([]string{"a"},1))
                      fmt.Printf("Array %v after rotation %v\n", []string{"a","b"}, rotationBySlicing[string]([]string{"a","b"},1))
                      fmt.Printf("Array %v after rotation %v\n", []string{"a","b","c"}, rotationBySlicing[string]([]string{"a","b","c"},1))
                      fmt.Printf("Array %v after rotation %v\n", []string{"a", "b", "c", "d"}, rotationBySlicing[string]([]string{"a", "b", "c", "d"},1))
                      fmt.Printf("Slice %v after rotation %v\n", []int{1,2,3,4,5,6,7}, rotationBySlicing[int]([]int{1,2,3,4,5,6,7}, 3))
                  
                  
                  Array [] after rotation []
                  Array [a] after rotation [a]
                  Array [a b] after rotation [b a]
                  Array [a b c] after rotation [b c a]
                  Array [a b c d] after rotation [b c d a]
                  Array [1 2 3 4 5 6 7] after rotation [4 5 6 7 1 2 3]
                  
                  
                  

                  还有说明:

                  其中 k 是非负数

                  ,为了完整起见,代码应在 k 小于 0 时处理大小写

                  【讨论】:

                    猜你喜欢
                    • 2023-03-18
                    • 2023-04-08
                    • 1970-01-01
                    • 2018-10-12
                    • 1970-01-01
                    • 1970-01-01
                    • 2016-07-18
                    • 2021-11-02
                    • 2021-05-02
                    相关资源
                    最近更新 更多