【问题标题】:Rotate Array LeetCode (189)旋转数组 LeetCode (189)
【发布时间】:2021-10-01 11:14:18
【问题描述】:

问题如下:

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

这是我的代码:

 class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int r =nums.size()-k;
        vector<int>::iterator it;
        it = nums.begin();
        for(int i=0;i<r;i++){
         nums.push_back(nums[0]);
          nums.erase(it);
      }
    }
};

测试用例 1:
输入:nums = [1,2,3,4,5,6,7], k = 3
输出:[5,6,7,1,2,3,4]

在这里,我的代码编译成功并且给出了正确的解决方案。

测试用例 2:
输入:nums = [-1,-100,3,99], k = 2
输出:[3,99,-1,-100]

这里,所有问题都开始了,我的代码给出了以下错误:

=================================================================
==32==ERROR: AddressSanitizer: heap-use-after-free on address 0x602000000094 at pc 0x0000003189cf bp 0x7ffe0e44adf0 sp 0x7ffe0e44a5b8
READ of size 68719476672 at 0x602000000094 thread T0
    #5 0x7f15fa2470b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
0x6020000000a0 is located 0 bytes to the right of 16-byte region [0x602000000090,0x6020000000a0)
freed by thread T0 here:
    #4 0x7f15fa2470b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
previously allocated by thread T0 here:
    #6 0x7f15fa2470b2  (/lib/x86_64-linux-gnu/libc.so.6+0x270b2)
Shadow bytes around the buggy address:
  0x0c047fff7fc0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fd0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7fe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff7ff0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c047fff8000: fa fa fd fa fa fa fd fa fa fa fd fa fa fa fd fa
=>0x0c047fff8010: fa fa[fd]fd fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8020: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8030: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8040: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8050: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c047fff8060: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==32==ABORTING

我是这个错误,请帮忙。

【问题讨论】:

  • 这是人们能想到的最低效的解决方案。看看std::rotate
  • 谢谢!
  • @churill 真的效率最低吗?你确定吗 ?如果面试官不想要 STL 方法怎么办?我可以认为比这更低效
  • 不使用 stl 不是借口 ;) 标准库只是提供了常用算法和数据结构的实现。而是将每个元素移动 n 次 1 最好将其一次移动 n 个位置。

标签: c++ arrays runtime-error


【解决方案1】:

std::vector 的迭代器可能会被push_back() 失效。

您应该直接使用nums.begin(),而不用保存迭代器进行擦除。

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int r =nums.size()-k;
        // this iterator may be invalidated
        //vector<int>::iterator it;
        //it = nums.begin();
        for(int i=0;i<r;i++){
            nums.push_back(nums[0]);
            // use begin() directly
            //nums.erase(it);
            nums.erase(nums.begin());
        }
    }
};

【讨论】:

  • ..如果它没有被push_back 失效,它肯定会被erase 失效
  • nums.size()-k k 可能大于 size
  • 谢谢你我现在明白了
【解决方案2】:

代码崩溃是因为在调用push_back之后it会变成invalidated,为了解决这个问题我们可以直接调用begin

class Solution {
public:
    void rotate(vector<int>& nums, int k) {
        int r =nums.size()- (k % nums.size());
        for(int i=0;i<r;i++){
            nums.push_back(nums[0]);
            nums.erase(nums.begin());
        }
    }
};

您代码中的算法与右旋转不同,您使用的是左旋转。右旋转需要在字体中插入最后一个元素,然后擦除最后一个元素,并且还需要对向量的长度取模,避免不必要的旋转,否则会造成浪费,可接受的代码可能是这样的:

class Solution {
 public:
  void rotate(vector<int>& nums, int k) {
    int r = k % nums.size();
    for (int i = 0; i < r; i++) {
      nums.insert(nums.begin(), nums.back());
      nums.erase(std::prev(nums.end()));
    }
  }
};

我们也可以调用STL算法:rotate,向右旋转,这里需要使用反向迭代器:

class Solution {
 public:
  void rotate(vector<int>& nums, int k) {
    int r = k % nums.size();
    std::rotate(nums.rbegin(), nums.rbegin() + r, nums.rend());
  }
};

您的算法会导致向量元素在每次插入到前面时都会移动,效率不高,想想我们有一个很大的向量,移动所有元素将是一个瓶颈。

STL 版本可能具有其他一些性能增强,因为它可以批量移动元素范围,而不是一个一个地交换元素。

我们也可以调用std::reverse 3 次来实现我们自己的rotate

class Solution {
 public:
  void rotate(vector<int>& nums, int k) {
    int r = k % nums.size();
    std::reverse(nums.begin(), nums.end());
    std::reverse(nums.begin(), nums.begin() + r);
    std::reverse(nums.begin() + r, nums.end());
  }
};

最后两个版本比前两个版本快很多,推荐使用。

【讨论】:

  • 非常感谢,现在我明白了。成功了!!
猜你喜欢
  • 2022-01-18
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 2021-04-14
  • 1970-01-01
  • 1970-01-01
  • 2016-07-18
相关资源
最近更新 更多