编写一个程序,在 8 个可能的方向线性遍历的 n*m 矩阵中找到 K 大小窗口的最大和

Posted

技术标签:

【中文标题】编写一个程序,在 8 个可能的方向线性遍历的 n*m 矩阵中找到 K 大小窗口的最大和【英文标题】:Write a program to find max sum of K size window in n*m matrix traversing in 8 possible directions linearly 【发布时间】:2022-01-20 07:13:58 【问题描述】:

我最近在一家公司面试,最后一轮被拒绝了,只有一个问题。

面试官陈述了一个 n*m 长度的二维数组。我们可以从左到右从上到下以及对角线遍历。提供了一个固定的窗口 k 来找到遍历任何方式的一维数组窗口的最大总和。

数组未排序且没有任何模式。边缘不能重叠/滚动。

1

Example:- 2 3 4 5 2
          3 1 8 9 9
          4 4 3 2 8 
          3 4 7 7 7
n=4
m=5
k=3

Output :- Max Sum= 26
Explanations:- (8+9+9)
              second row has the largest sum window with size 3.

我给出了遍历所有方向的蛮力方法(8)以及滑动窗口方法来计算最大和。

很遗憾我被拒绝了,我仍然没有找到针对面试官提出的问题的优化解决方案。

我编写的代码-

(忽略所需的输入)

class sliding 
    public static void main(int ar[][], int k) 
        int m = ar.length;
        int n = ar[0].length;
        int sum = 0;

        if (m >= k)  //for row-wise max window
            for (int i = 0; i < m; i++) 
                int tempSum = 0;
                int x = 0;
                int j = 0;
                while (j < n) 
                    tempSum += ar[i][j];
                    if (j - x + 1 < k)
                        j++;
                    else if (j - x + 1 == k) 
                        sum = Math.max(tempSum, sum);
                        tempSum = tempSum - ar[i][x];
                        x++;
                        j++;
                    
                
            
        
        if (n >= k) //for column-wise max window
        
            for (int i = 0; i < n; i++) 
                int tempSum = 0;
                int x = 0;
                int j = 0;
                while (j < m) 
                    tempSum += ar[i]][j];
                if (j - x + 1 < k)
                    j++;
                else if (j - x + 1 == k) 
                    sum = Math.max(tempSum, sum);
                    temSum = tempSum - ar[i][x];
                    x++;
                    j++;
                
            
        
    
    //for diagonal-wise max
    if (n >= k && m >= k) 
        for (int i = 0; i < m; i++) 
            for (int j = 0; j < n; j++) 
                int x = 0;
                int p = i;
                int q = j;
                int p_initial = p;
                int q_initial = q;
                int tempSum = 0;
                while (p <= m - k && q <= n - k) 
                    if (x < k) 
                        tempSum += ar[p++][q++];
                        x++;
                     else if (x == k) 
                        sum = Math.max(tempSum, sum);
                        tempSum -= ar[p_initial][q_initial];
                        p_initial++;
                        q_initial++;
                    

                
            
        
    
// sum variable will store the final answer

复杂度 - O(n^3)

谁能优化我的方法或提供更好的解决方案。

【问题讨论】:

什么是“固定窗口k”?穿越:从哪里到哪里?你的解释难以理解。 8 个方向?我可能缺乏想象力,但左右,上下,两条对角线,我只数4 是否允许负值? @trincot 是的,允许负值 @YvesDaoust 固定窗口表示任何可能方向的K个连续数 【参考方案1】:

要覆盖主对角线方向,请使用索引ar[i+j][j] 而不是ar[i][j]。确保覆盖整个矩阵,同时确保0≤i+j&lt;n0≤j&lt;m。对于给定的j-j≤i&lt;n-j,因此外部 for 循环位于 -m&lt;i&lt;n。内部的while循环在max(0,-i)≤j&lt;min(n-i,n)

内部的while循环保持类似的结构,过程仍然是O(nm)

第二条对角线是ar[i-j][j]

【讨论】:

我喜欢你的方法,能否请您提及仅用于索引的对角线遍历代码,这样对我来说更容易......【参考方案2】:
public int findMaximumSum(int[][] matrix, int key) 
    int y = matrix.length - 1, x = matrix[0].length - 1;
    int max = 0;
    for (int i = 0; i <= y; i++) 
        for (int i1 = 0, j = key - 1; j <= x; j++, i1++) 
            int sum = matrix[i][i1] + matrix[i][j] + matrix[i][(i1 + j) / 2];
            max = Math.max(max, sum);
        
    
    return max;

【讨论】:

我想要对角线总和,而不仅仅是行总和 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。【参考方案3】:

你可以线性地找到最大子序列。

给定序列2 3 4 5 2k=32 3 4sum=9 开始并使用两个索引 - 一个指向2 和一个指向4 - 转发它们相应地修改sum

第一步:sum=9-2+5=12 第二步:sum=12-3+2=11

这使您可以线性选择max,这比使用 蛮力解决方案要好得多

【讨论】:

我使用这种滑动窗口的方法来找到最大和,但我必须行进 8 个方向,因此我在那里使用了蛮力,请你帮我在 2d 矩阵中线性地找到最大和 所以你没有实现暴力算法。你给出了什么样的复杂性分析? 是的,我使用蛮力循环以行方式、列方式和 2 对角方式行进,并将最大答案存储在变量中。因此,我不得不对行、列和对角线使用滑动窗口方法 4 次。我的面试官回答说这不是优化的方法。 当你被问及复杂性时,你的回答是什么? O(n²)(或更准确地说是O(nk))方法是为每个单元格计算下一个k 元素。每个单元格都有滑动窗口,您减去并添加一个单位:这是O(n)。如果你告诉,或者以 的方式编码,可能面试官没有正确理解你滑动数组的想法,并且正确地(恕我直言)拒绝了你。 (这里n表示单元格总数,即n*m

以上是关于编写一个程序,在 8 个可能的方向线性遍历的 n*m 矩阵中找到 K 大小窗口的最大和的主要内容,如果未能解决你的问题,请参考以下文章

对角线遍历

vijos 1471 线性DP+贪心

如何遍历列表的前 n 个元素?

编写高质量代码改善C#程序的157个建议——建议17:多数情况下使用foreach进行循环遍历

498#对角线遍历

线性空间/线性基