Python Snail算法-控制遍历的最大/最小位置
为了好玩,我正在研究代码战中的一个问题,我遇到了一些问题:Python Snail算法-控制遍历的最大/最小位置,python,algorithm,list,refactoring,traversal,Python,Algorithm,List,Refactoring,Traversal,为了好玩,我正在研究代码战中的一个问题,我遇到了一些问题: 理解我需要修改代码的地方,以便正确控制m和n的“转折点”,使它们开始减少而不是增加 适当地重构此代码 该算法的目的是像“蜗牛”一样遍历二维列表,例如 应该回来 [1,2,3,6,9,8,7,4,5] 对于任何大小为n*n的列表 我在数学或计算机科学方面没有很强的背景,但我真的很喜欢这两个方面,并试图深入理解这些问题 例如,我知道,如果n表示二维列表的行,m表示二维列表的列,我需要将蜗牛的每个“电路”的最小n增加1,并将每个电路的最大m
[1,2,3,6,9,8,7,4,5]
对于任何大小为n*n的列表
我在数学或计算机科学方面没有很强的背景,但我真的很喜欢这两个方面,并试图深入理解这些问题
例如,我知道,如果n
表示二维列表的行,m
表示二维列表的列,我需要将蜗牛的每个“电路”的最小n
增加1,并将每个电路的最大m
减少,但我很难理解在哪里需要这样做
我已经简单地看了一些递归解决方案,但在我开始深入研究它们之前,我希望有人能看看这个,帮助我理解我的想法完全错误的地方
def蜗牛(阵列):
新蜗牛=[]
n、 m=0,0
j=1
而j 0:
new_.append(数组[n][m])
m-=1
当n>0时:
new_.append(数组[n][m])
n-=1
m+=1
n+=1
j+=1
归还新蜗牛
目前,该算法在3x3 2D列表上的输出为
[1,2,3,6,9,8,7,4,5,4]
,这意味着我在到达终点后会向后移动
在更大的4x4 2D列表中
array = [[1,2,3,4],
[4,5,6,7],
[8,9,10,11],
[12,13,14,15]]
输出是[1,2,3,4,7,11,15,14,13,12,8,4,5,4]
,因此我在第一行来回移动
感谢您的关注,我希望这符合SO问题的指导原则。我更关心的是理解为什么我的代码是错误的/糟糕的实践
更新
我相信我对这个问题有了更好的理解,并取得了一些进展,但让我痛苦的仍然是清单上的界限。我觉得我在这方面真的很弱。我最终在一个方向上走得太远了,我所有的解决方案都是徒劳的
def蜗牛(阵列):
新蜗牛=[]
已访问=“*”
i、 j=0,0
当前\u dir=“右”
def更改方向(方向):
如果方向==“右”:
返回“向下”
elif方向==“向下”:
返回“左”
elif方向==“左”:
返回“向上”
elif方向==“向上”:
返回“正确”
def移动(IPO、JPO、方向):
i、 j=首次公开募股,JPO
如果i==-1:
i+=1
elif i==len(数组):
i-=1
elif j==-1:
j+=1
elif j==len(数组):
j-=1
如果方向==“右”:
返回i,j+1
elif方向==“向下”:
返回i+1,j
elif方向==“左”:
返回i,j-1
elif方向==“向上”:
返回i-1,j
新的\u.append(数组[0][0])
数组[0][0]=“*”
而len(新蜗牛) 如果0我只提供一个想法,代码应该由您自己编写
蜗牛的头部有四个方向,依次是右(j+=1)、下(i+=1)、左(j-=1)、上(i-=1)
蜗牛将沿着圆圈上的这四个方向(右、下、左、上、右、下、左……)转下一个方向直到到达边界或访问的号码。当蜗牛无法行走到任何网格时结束
的定义不能走到任何网格
:不能在方向和下一个方向跨入下一个网格
带注释的示例代码
directions = [
lambda i, j: (i, j + 1),
lambda i, j: (i + 1, j),
lambda i, j: (i, j - 1),
lambda i, j: (i - 1, j),
]
array = [[1,2,3,4],
[4,5,6,7],
[8,9,10,11],
[12,13,14,15]]
def in_matrix(i, j):
return 0 <= i < len(array) and 0 <= j < len(array)
def is_visited(i, j):
return array[i][j] == 0
def snail(array):
direction_cnt = 0
i, j = 0, 0
ret = []
ret.append(array[i][j])
array[i][j] = 0 # mark as visited
while True:
direction_func = directions[direction_cnt % 4] # turning directions in circle
tmp_i, tmp_j = direction_func(i, j) # attempt to head one step
if (not in_matrix(tmp_i, tmp_j)) or is_visited(tmp_i, tmp_j): # over border or visted
direction_cnt += 1 # change direction
else:
i, j = tmp_i, tmp_j # confirm this step
ret.append(array[i][j])
array[i][j] = 0 # mark as visited
if len(ret) == len(array)**2: # simple terminal criteria
return ret
if __name__ == '__main__':
print snail(array)
方向=[
λi,j:(i,j+1),
λi,j:(i+1,j),
λi,j:(i,j-1),
λi,j:(i-1,j),
]
数组=[[1,2,3,4],
[4,5,6,7],
[8,9,10,11],
[12,13,14,15]]
def在_矩阵中(i,j):
返回0回答关于“什么是错误的”的问题:
在这一部分,您告诉解释器“M是1”(实际上,M=0+1,但结果相同)
然后你说“如果M不是==0(否则的情况),M=M-1”
因此,在j+=1之后的第一次迭代中,m是1,然后进入第二种情况,使其向后移动
您可以将“m>0”改为“m>j”,因为您在每个循环中增加j 1
编辑:
条件的第一部分也应该重新编写为“m==j和n==j”,而不是0。否则,它将总是在第一次执行后进入第二种情况。考虑到您谈到的重构代码,这里有一种可能的方法。因此,有几点可以帮助您从不同的角度看待这个问题。
首先,我们设定了一些东西:方向,以及蜗牛的下一个方向。由于方向是一个循环(右、下、左、上、右、下…),我们可以用一个函数来表示它,next\u direction
。
此外,创建一个只“更新”位置的函数可以使代码更易于阅读
RIGHT = 0
DOWN = 1
LEFT = 2
UP = 3
NB_DIRECTIONS = 4
def next_direction(direction):
return (direction + 1) % NB_DIRECTIONS
def update_position(position, direction):
x, y = position
if direction == RIGHT:
return x + 1, y
elif direction == DOWN:
return x, y + 1
elif direction == LEFT:
return x - 1, y
elif direction == UP:
return x, y - 1
然后使用函数从数组中获取值,并将数组中的值设置为“已访问”
def get_value(array, position):
x, y = position
return array[y][x]
def set_as_visited(array, position):
x, y = position
array[y][x] = '*'
def is_visited(array, position):
return get_value(array, position) == '*'
以及“主要”功能。我在评论中使用了您的想法,用'*'
替换了阵列中访问过的位置。既然我们这样做了,就不用检查边界,我们可以用“*”
包围整个矩阵
def snail_arr(array):
# compute the array size
array_size = len(array) * len(array[0])
# surround the array of '*'
array = [['*' for _ in range(len(array[0]) + 2)]] + [
['*'] + array[i] + ['*']
for i in range(len(array))
] + [['*' for _ in range(len(array[0]) + 2)]]
# initialize position and direction
position = 1, 1
direction = RIGHT
result = [get_value(array, position)]
set_as_visited(array, position)
nb_visited = 1
while nb_visited < array_size:
new_position = update_position(position, direction)
if not is_visited(array, new_position):
result += [get_value(array, new_position)]
set_as_visited(array, new_position)
position = new_position
nb_visited += 1
else:
direction = next_direction(direction)
return result
编辑:
要使用数组边界执行此操作,可以添加一个新函数来检查:
def is_in_bounds(array, position): # valid only for square array
x, y = position
array_size = len(array)
return (0 <= x < array_size) and (0 <= y < array_size)
def是_in_边界(数组,位置):#仅对方形数组有效
x、 y=位置
数组_size=len(数组)
return(0这是螺旋序矩阵遍历的有效方法
def snail_arr(array):
# compute the array size
array_size = len(array) * len(array[0])
# surround the array of '*'
array = [['*' for _ in range(len(array[0]) + 2)]] + [
['*'] + array[i] + ['*']
for i in range(len(array))
] + [['*' for _ in range(len(array[0]) + 2)]]
# initialize position and direction
position = 1, 1
direction = RIGHT
result = [get_value(array, position)]
set_as_visited(array, position)
nb_visited = 1
while nb_visited < array_size:
new_position = update_position(position, direction)
if not is_visited(array, new_position):
result += [get_value(array, new_position)]
set_as_visited(array, new_position)
position = new_position
nb_visited += 1
else:
direction = next_direction(direction)
return result
array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
print(snail_arr(array))
# [1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5, 6, 7, 11, 10]
def is_in_bounds(array, position): # valid only for square array
x, y = position
array_size = len(array)
return (0 <= x < array_size) and (0 <= y < array_size)
vector<int> Solution::spiralOrder(const vector<vector<int>> &arr) {
int r = arr.size();
int c = arr[0].size();
int left = 0;
int right = c-1;
int top = 0;
int bottom = r-1;
int dir = 0;
vector<int> ans;
while(left <= right && top <= bottom){
if(dir == 0){
for(int i = left; i<=right; i++){
ans.push_back(arr[top][i]);
}
top++;
dir = 1;
}
else if(dir == 1){
for(int i = top; i<=bottom; i++){
ans.push_back(arr[i][right]);
}
right--;
dir = 2;
}
else if(dir == 2){
for(int i = right; i>=left; i--){
ans.push_back(arr[bottom][i]);
}
bottom--;
dir = 3;
}
else if(dir == 3){
for(int i = bottom; i>=top; i--){
ans.push_back(arr[i][left]);
}
left++;;
dir = 0;
}
}
return ans;