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

为了好玩,我正在研究代码战中的一个问题,我遇到了一些问题:

  • 理解我需要修改代码的地方,以便正确控制m和n的“转折点”,使它们开始减少而不是增加

  • 适当地重构此代码

  • 该算法的目的是像“蜗牛”一样遍历二维列表,例如

    应该回来

    [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;