编写一个程序,在 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<n
和0≤j<m
。对于给定的j
,-j≤i<n-j
,因此外部 for 循环位于 -m<i<n
。内部的while循环在max(0,-i)≤j<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 2
和k=3
从2 3 4
和sum=9
开始并使用两个索引 - 一个指向2
和一个指向4
- 转发它们相应地修改sum
:
sum=9-2+5=12
第二步:sum=12-3+2=11
这使您可以线性选择max
,这比使用n²
蛮力解决方案要好得多
【讨论】:
我使用这种滑动窗口的方法来找到最大和,但我必须行进 8 个方向,因此我在那里使用了蛮力,请你帮我在 2d 矩阵中线性地找到最大和 所以你没有实现暴力算法。你给出了什么样的复杂性分析? 是的,我使用蛮力循环以行方式、列方式和 2 对角方式行进,并将最大答案存储在变量中。因此,我不得不对行、列和对角线使用滑动窗口方法 4 次。我的面试官回答说这不是优化的方法。 当你被问及复杂性时,你的回答是什么?O(n²)
(或更准确地说是O(nk)
)方法是为每个单元格计算下一个k
元素。每个单元格都有滑动窗口,您减去并添加一个单位:这是O(n)
。如果你告诉n²
,或者以n²
的方式编码,可能面试官没有正确理解你滑动数组的想法,并且正确地(恕我直言)拒绝了你。 (这里n
表示单元格总数,即n*m
)以上是关于编写一个程序,在 8 个可能的方向线性遍历的 n*m 矩阵中找到 K 大小窗口的最大和的主要内容,如果未能解决你的问题,请参考以下文章