【问题标题】:rotating the array anti-clockwise, run time issues逆时针旋转阵列,运行时间问题
【发布时间】:2020-05-23 07:46:21
【问题描述】:

在问题中,我必须将数组中的数据逆时针旋转 d 个数字。但是运行所需的时间比提交资格所需的时间要长。谁能帮助我优化代码以在更短的时间内运行它?谢谢!

代码如下:

int main() {
int test_cases,size,d;
std::cin>>test_cases;
while(test_cases!=0){
std::cin>>size>>d;
int ar[size];
for(int i=0;i<size;i++){
    std::cin>>ar[i];
}
while(d!=0){
    int x = ar[0];
    for(int i=1;i<size;i++){
        ar[i-1]=ar[i];
    }
    ar[size-1]=x;
    d--;
}
for(int i=0;i<size;i++){
    std::cout<<ar[i]<<" ";
}
test_cases--;
cout<<endl;
}}

【问题讨论】:

  • int arr[size]; 声明了一个变长数组,这是一个非标准特性,你最好使用std::vector。搜索一次不旋转一步的算法。或者只是作弊并使用std::rotate
  • 要将阵列向左“旋转”10 个位置,您将整个阵列向左旋转 1 个位置 10 次。您可以一次旋转整个数组。
  • 您的算法每次测试 O(size * d),但可以减少到每次测试 O(d)。参见例如Geeks for geeks explanation。使用额外的数组相对容易,而没有额外的数组则稍微复杂一些。
  • @Bob__ 我不会打电话使用 std::rotate 作弊:)

标签: c++ arrays data-structures compile-time


【解决方案1】:

您应该按照 cmets 中的建议移动每个元素一次。找出一个算法来做到这一点并不难。但是,为什么要重新发明轮子呢?

您可以简单地使用std::rotate。我将假设 逆时针 表示 向左,并且数组从左侧开始并在右侧结束:)。

std::vector<int> v {1,2,3};
size_t dist = 4; // rotate 4 to the left
std::rotate(v.begin(), v.begin() + dist % v.size(), v.end());

如果你真的坚持要重新发明轮子,我想有很多可能的算法。下面的示例从索引idx = 0 开始,并将值存储在索引idx_moved = idx + dist 处,其中dist 是旋转距离。然后我们对idx = idx_moved 执行相同的操作,并重复此操作 N 次,其中 N 是数组的大小。我在这里使用了std::vector,但这并没有改变算法。

std::vector<int> v {1,2,3,4,5};
size_t dist = 3; // distance to move to the left

size_t idx = 0;
int tmp = v[0]; // store the initial value

for (size_t it = 0; it < v.size(); ++it)
{
    size_t idx_moved = (idx + dist) % v.size();
    v[idx] = v[idx_moved];
    idx = idx_moved;
}
v[dist * (v.size() -1 ) % v.size()] = tmp; // store the initial value back

【讨论】:

  • 我想用逻辑而不是预定义的函数来解决它,所以..
  • @NitinRaina 我添加了一个不使用 stl 的示例。但是,如果您有 C++ 测试,请使用 stl.与重新发明轮子相比,考官可能会给你更多的分数:)
【解决方案2】:

为了使其更快,您可以使用A Juggling Algorithmhere 很好地解释了它是如何工作的。主要原则是您不是逐个移动元素,而是在相等的集合内移动元素。

【讨论】:

    【解决方案3】:

    虽然问题与向左旋转(如您所说的逆时针)有关,但我们始终可以将其重新表述为向右旋转给定(正)偏移量。

    例如,给定以下大小为 n = 9

    的数组(在 C++ 中应该是 std::vector) 1 2 3 4 5 6 7 8 9

    向左旋转 3 个位置(d = 3,在 OP 的问题中),相当于向右旋转 6 个位置(我们称这个偏移量为 k,因此 k = 6):

    4 5 6 7 8 9 1 2 3

    如果可以使用额外的内存,最简单的方法应该是将前 n - k 个元素(或最后一个 k 个元素)复制到临时缓冲区中,移动剩余的 k 个在开头(或第一个 n - k 在末尾),然后将元素从缓冲区复制回最后一个位置(或者,你知道...)。

    [1 2 3 4 5 6 7 8 9] [ ] ^ ^ ^ 复制第一个元素 [1 2 3 4 5 6 7 8 9] [1 2 3] ^ ^ ^ ^ ^ ^ 移到开头 [4 5 6 7 8 9 7 8 9] [1 2 3] ^ ^ ^ 复制回来 [4 5 6 7 8 9 1 2 3] [1 2 3]

    如果你不能并且分配需要修改数组,那么其他答案中显示的杂耍算法的一个很好的替代方案只需要三个反向:

    [1 2 3 4 5 6 7 8 9] ^ ^ ^ 反转前n-k个元素 [3 2 1 4 5 6 7 8 9] ^ ^ ^ ^ ^ ^ 反转最后k个元素 [3 2 1 9 8 7 6 5 4] ^ ^ ^ ^ ^ ^ ^ ^ 全部反转 [4 5 6 7 8 9 1 2 3]

    如果你正在编写真正的代码,你最好使用std::rotate

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-08
      • 1970-01-01
      相关资源
      最近更新 更多