【问题标题】:Rotating matrix by 90 degress in anticlockwise direction , where am i going wrong逆时针方向旋转矩阵90度,我哪里错了
【发布时间】:2020-11-30 07:33:07
【问题描述】:

给定一个大小为 N x N 的方阵 mat[ ][ ]。任务是在不使用任何额外空间的情况下将其逆时针方向旋转 90 度。 Problem Link

我的逻辑 - 对于矩阵 N x N,通过使用临时变量 X-1 时间从左列 -> 底行 -> 右列 -> 顶行交换元素,以逆时针方向旋转外部窗口,其中 X 是外窗的尺寸。我不知道为什么它不起作用。请帮我找出问题。

#include<bits/stdc++.h>
using namespace std;

int main() {
int t=1; cin>>t;
while (t--) {
    int n; cin>>n; vector<vector<int>>a(n,vector<int>(n));
    for(int i=0;i<n;i++) for(int j=0;j<n;j++) cin>>a[i][j];
    
    for(int k=0;k<n;k++) {
        int i=k, j=0, p=n-1-k, q=p-i, temp;
        while (q-- && i<p) {
            temp=a[i][i];j=i;
            while (j<=p) {
                swap(temp, a[j][i]);j++; 
            }j=i+1; 
            while (j<=p) {
                swap(temp, a[p][j]);j++;
            }j=p-1;
            while (j>=i) {
                swap(temp, a[j][p]); j--;
            }j=p-1;
            while (j>=i) {
                swap(temp, a[i][j]); j--;
            }
        }
    }
    for(int i=0;i<n;i++) {
         for(int j=0;j<n;j++) cout<<a[i][j]<<" ";
        cout<<"\n";
    }
    cout<<"\n";
}
}

谢谢

【问题讨论】:

  • 请不要使用这样的宏。它使代码更难阅读。
  • 看到 #define FOR ... 停止阅读。
  • cin&gt;&gt;n; int a[n][n]; 不是有效的 C++。请改用vector
  • 比无效更糟糕的是,当编译器扩展允许 cin&gt;&gt;n; int a[n][n]; 允许用户非常非常容易地溢出堆栈时。低至 1000 的 n 可能会毁了你一整天。
  • 在开发环境的调试器中使用一个小的输入集(如 1 2 1 2 3 4)单步执行程序,并观察发生的情况。通常这会很有帮助。

标签: c++ algorithm matrix logic implementation


【解决方案1】:

[注意:我之前的解决方案使用了额外的内存,而这个没有。因此,我删除了以前的解决方案,并对其进行了全面更新以提供新的解决方案]。

好吧,如果我们能够使用额外的空间,这个问题可以很容易地解决,但事实并非如此。无论如何,也可以轻松解决,无需额外占用额外空间。

首先,让我解释一下我对这个问题的解决方案。然后,我将告诉您代码中的错误行为。我的解决方案与您的方法类似。它将输入数组视为环或循环的层。见下文:

0 0 0 0 0
0 1 1 1 0
0 1 2 1 0
0 1 1 1 0
0 0 0 0 0

外环是0,内环是1,依此类推……

现在,为了争论,假设我们使用了额外的空间 b(虽然我们不会在解决方案中使用这个空间)。另外,让我们假设,b 是包含旋转矩阵的已解决数组。那么,我们可以说:

b[(n + n - j - 1) % n][i] = a[i][j] // for any i, j
// here "n" is dimension of matrix
// "i", represents ith indexed row of a
// "j", represents jth indexed column of a

// if you having problem, how this thing just dropped from sky, then
// just write down in paper, for some index (x, y) what it becomes when it is rotated
// you'll see some formula like I've described above

好的,现在,如果您对公式很清楚,让我描述一下它如何帮助解决问题:

在上一个环图中(我用来显示环的那个),你可以看到0的环的角元素只是相互改变,即矩阵的角元素只是相互交换位置旋转,它们从不干扰其他元素。这也适用于其他元素。一个组中总是有四个元素,它们只是相互交换位置!只有一个例外是中心(如果 n 是奇数)。而且中心永远不会改变位置......

如果你也观察过四个元素的循环/组,它们只是相互交换位置,那么我们可以从当前元素的位置找出下一个元素的位置并放置当前元素的值,我们就是完成... 那么,如何找出下一个位置的价值。注意,我们已经讨论过了,b 的结果是如何从a 计算出来的。所以,我们可以在下面写一些东西:

pair<int, int> getNext(pair<int, int> x, int n) {
    return make_pair((n + n - x.second - 1) % n, x.first);
}

现在,来看看戒指,有多少我们应该关心的,那就是(n/2) 戒指。所以,我们将只去每个环,遍历每个环的第一行的元素(最后一个除外,因为它包含在角落中)并运行一个四循环以正确替换位置的值。完整代码如下:

#include <iostream>
#include <string>

#define N 128

// returns next postition based on present position
// next position means where the present position value should
// be transferred after rotation
pair<int, int> getNext(pair<int, int> x, int n) {
    return make_pair((n + n - x.second - 1) % n, x.first);
}

int main() {
    int a[N][N];

    int n;
    scanf("%d", &n);

    for(int i=0; i<n; i++) {
        for(int j=0; j<n; j++) {
            scanf("%d", &a[i][j]);
        }
    }
    
    for(int h = 0; h < (n / 2); h++) {
        int s = h;
        int e = n - h - 1;

        for(int k = s; k < e; k++) {
            auto p = make_pair(s, k); // row = s, and col = k
            int t = a[p.first][p.second];

            for(int c=0; c<4; c++) {
                auto p2 = getNext(p, n);
                int temp = a[p2.first][p2.second];

                a[p2.first][p2.second] = t;

                t = temp;
                p = p2;
            }
        }
    }

    for(int i=0; i<n; i++) {
        for(int j=0; j<n; j++) {
            printf("%d ", a[i][j]);
        }
        printf("\n");
    }

    return 0;
}

现在,您的代码有什么问题:

我想,你已经明白了,你的算法不正确......而且实现也有问题......

[P.S.]:请不要只是复制粘贴代码,首先要了解它。另外,以某种方式编写代码,以便其他人可以阅读...如果您在我提供的算法中发现任何错误,或者您可能无法理解任何概念,请在评论中告诉我...

【讨论】:

  • 请注意,问题明确表示“不使用任何额外空间”。
  • @cigien 对不起,我的错...错过了...编辑代码...感谢您指出...
  • @ChandanKumar,我提供了一个新的解决方案(无需额外空间即可工作),它既简单又优雅..很抱歉迟到发布这个答案......陷入了一些工作......
【解决方案2】:

我想建议一种看起来更简单的方法。

假设您有一个像这样的char 类型的向量。

a b c d 
e f g h 
i j k l 
m n o p

结果向量必须看起来像

d h l p 
c g k o 
b f j n 
a e i m 

结果向量可以分两步构建。

第一步,交换源向量的行。

m n o p 
i j k l 
e f g h 
a b c d 

在第二步中,有相对于侧对角线的交换元素,例如'm''d' 交换,'n''h' 交换,'o''l' 交换。然后对从向量末尾算起的第二行第二列的元素重复这些操作。

这是一个演示程序。

#include <iostream>
#include <utility>
#include <vector>

int main() 
{
    std::vector<std::vector<char>> a =
    {
        { 'a', 'b', 'c', 'd' },
        { 'e', 'f', 'g', 'h' },
        { 'i', 'j', 'k', 'l' },
        { 'm', 'n', 'o', 'p' },
    };
    
    auto n = a.size();
    
    for ( const auto &row : a )
    {
        for ( const auto &item : row )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    }
    std::cout << '\n';
    
    for ( size_t i = 0; i < n / 2; i++ )
    {
        std::swap( a[i], a[n-i-1] );
    }

    for ( const auto &row : a )
    {
        for ( const auto &item : row )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    }
    std::cout << '\n';
    
    for ( size_t i = 0; i + 1 < n; i++ )
    {
        for ( size_t j = 0; j + i + 1 < n; j++ )
        {
            std::swap( a[i][j], a[n-j -1][n - i -1]);
        }
    }
    
    for ( const auto &row : a )
    {
        for ( const auto &item : row )
        {
            std::cout << item << ' ';
        }
        std::cout << '\n';
    }
    std::cout << '\n';

    return 0;
} 

程序输出是

a b c d 
e f g h 
i j k l 
m n o p 

m n o p 
i j k l 
e f g h 
a b c d 

d h l p 
c g k o 
b f j n 
a e i m 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-08
    • 2019-11-05
    • 2021-08-07
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 2013-05-05
    相关资源
    最近更新 更多