Algorithm 寻找最佳解决方案

Algorithm 寻找最佳解决方案,algorithm,data-structures,Algorithm,Data Structures,这是亚马逊的采访问题之一。 给定一个0和1的2D数组,我们需要找到最大大小的模式。 模式如下: 尺寸=1: 1 1 1 1 1 尺寸=2: 1 1 1 1 1 1 1 简单解决方案:遍历MxN矩阵的每个元素,搜索值为1的索引,检查左右条目是否为1,并注意索引上方和下方1的最大长度 寻找更好的解决方案。如果有人有线索,请发帖子 我假设围绕这样一个模式的任何1值都不会破坏它,因此它的大小也是1: 1 1 1 1 1 1 1 1 1 1 0 1 1

这是亚马逊的采访问题之一。 给定一个0和1的2D数组,我们需要找到最大大小的模式。 模式如下:

尺寸=1:

   1
 1 1 1 
   1
尺寸=2:

   1
   1 
 1 1 1 
   1 
   1
简单解决方案:遍历MxN矩阵的每个元素,搜索值为1的索引,检查左右条目是否为1,并注意索引上方和下方1的最大长度


寻找更好的解决方案。如果有人有线索,请发帖子

我假设围绕这样一个模式的任何1值都不会破坏它,因此它的大小也是1:

1 1 1 1
1 1 1 1
1 1 0 1
1 1 1 1
在这种情况下,我建议使用一种算法,在该算法中,您可以对每一列执行以下操作:

  • 将大小初始化为0
  • 对于此列中的每个单元格:
    • 推送堆栈上的当前大小;它表示从该单元格开始的向上方向上的1个值的数目
    • 如果此单元格中的值为1,则增大大小,否则将其设置为0
  • 将大小初始化为0
  • 对于此列中的每个单元格,但顺序相反:
    • 从堆栈中弹出最后一个值
    • 调用thisSize是弹出值和size值中最小的一个
    • 如果这个大小大于目前为止发现的最佳模式,并且当前单元格的两侧的值为1,则认为这是最好的模式。
    • 如果此单元格中的值为1,则增大大小,否则将其设置为0
  • 作为进一步的优化,只要当前单元格和网格顶部之间的距离小于我们之前发现的最大图案的大小,您就可以退出第二个循环

    下面是一个JavaScript实现:

    函数findPattern(a){
    变量行=a.length,
    cols=a[0]。长度,
    maxSize=-1,
    堆栈=[],
    行、列、位置、此大小;
    for(col=1;col最大大小;行--){
    thisSize=Math.min(size,stack.pop());
    如果(thisSize>=maxSize&&a[行][col-1]==1&&a[行][col+1]==1){
    maxSize=此大小;
    pos=[行,列];
    }
    大小=一行[列]==1?大小+1:0;
    }
    }
    返回[maxSize,pos];
    }
    //样本数据:
    变量a=[
    [0, 0, 1, 0, 0, 1, 0],
    [0, 0, 1, 1, 0, 1, 0],
    [1, 1, 1, 0, 0, 1, 1],
    [1, 0, 1, 0, 1, 1, 0],
    [1, 1, 1, 1, 0, 1, 0],
    [0, 1, 1, 1, 1, 1, 1],
    [0, 0, 1, 0, 0, 1, 0]];
    变量[大小,位置]=findPattern(a);
    console.log('Size'+Size++',中间在'+'行(位置[0]+1))
    
    +'和列'+(位置[1]+1)+'(第一行/列编号为1')我假设围绕这样一个模式的任何1值都不会破坏它,因此它的大小也是1:

    1 1 1 1
    1 1 1 1
    1 1 0 1
    1 1 1 1
    
    在这种情况下,我建议使用一种算法,在该算法中,您可以对每一列执行以下操作:

  • 将大小初始化为0
  • 对于此列中的每个单元格:
    • 推送堆栈上的当前大小;它表示从该单元格开始的向上方向上的1个值的数目
    • 如果此单元格中的值为1,则增大大小,否则将其设置为0
  • 将大小初始化为0
  • 对于此列中的每个单元格,但顺序相反:
    • 从堆栈中弹出最后一个值
    • 调用thisSize是弹出值和size值中最小的一个
    • 如果这个大小大于目前为止发现的最佳模式,并且当前单元格的两侧的值为1,则认为这是最好的模式。
    • 如果此单元格中的值为1,则增大大小,否则将其设置为0
  • 作为进一步的优化,只要当前单元格和网格顶部之间的距离小于我们之前发现的最大图案的大小,您就可以退出第二个循环

    下面是一个JavaScript实现:

    函数findPattern(a){
    变量行=a.length,
    cols=a[0]。长度,
    maxSize=-1,
    堆栈=[],
    行、列、位置、此大小;
    for(col=1;col最大大小;行--){
    thisSize=Math.min(size,stack.pop());
    如果(thisSize>=maxSize&&a[行][col-1]==1&&a[行][col+1]==1){
    maxSize=此大小;
    pos=[行,列];
    }
    大小=一行[列]==1?大小+1:0;
    }
    }
    返回[maxSize,pos];
    }
    //样本数据:
    变量a=[
    [0, 0, 1, 0, 0, 1, 0],
    [0, 0, 1, 1, 0, 1, 0],
    [1, 1, 1, 0, 0, 1, 1],
    [1, 0, 1, 0, 1, 1, 0],
    [1, 1, 1, 1, 0, 1, 0],
    [0, 1, 1, 1, 1, 1, 1],
    [0, 0, 1, 0, 0, 1, 0]];
    变量[大小,位置]=findPattern(a);
    console.log('Size'+Size++',中间在'+'行(位置[0]+1))
    
    +'和列'+(位置[1]+1)+'(第一行/列编号为1')以下使用的逻辑与trincot在其回答中提供的基本相同,但只要连续1中出现中断,就会进行反向扫描。这样就不需要构建显式堆栈

    运行时间应大致相同。我的方法的唯一优点是该算法使用
    private void DoIt()
    {
        var rslt = FindPattern(_sampleData);
        Console.WriteLine($"Result: {rslt.Size}, [{rslt.Row}, {rslt.Col}]");
    }
    
    private readonly int[,] _sampleData =
    {
        {0, 0, 1, 0, 0, 1, 0},
        {0, 0, 1, 1, 0, 1, 0},
        {1, 1, 1, 0, 0, 1, 1},
        {1, 0, 1, 0, 1, 1, 0},
        {1, 1, 1, 1, 0, 1, 0},
        {0, 1, 1, 1, 1, 1, 1},
        {0, 0, 1, 0, 0, 1, 0}
    };
    
    int rows = arr.length;
    int cols = arr[0].length;
    int min = rows < cols ? rows : cols;
    int diff = rows > cols ? rows - cols : cols - rows;
    
    // Initializing initial window params. The center most smallest window possible
    int first_r, first_c, last_r, last_c;
    first_r = (min - 1) / 2;
    first_c = (min - 1) / 2;
    last_r = rows < cols ? (rows / 2) : (cols / 2) + diff;
    last_c = rows > cols ? (cols / 2) : (rows / 2) + diff;
    
    public class PlusPattern {
    
        /**
         * Utility method to verify matrix dimensions
         *
         * @param a matrix to be verified
         * @return true if matrix size is greater than 0;
         */
        private static boolean isValid(int[][] a) {
            return a.length > 0 && a[0].length > 0;
        }
    
        /**
         * Finds the size of largest plus(+) pattern of given 'symbol' integer in an integer 2D matrix .
         *
         * The idea is to find for the biggest possible plus(+) pattern first around the central elements
         * of the matrix. If largest is found return the largest size. If largest possible + is not
         * found, store the size of whatever smaller than that was found and repeat search for 1 size
         * smaller + in the next outer window around the previous window.
         *
         * @param arr    matrix to be searched
         * @param symbol whose + patter is sought
         * @return the radius of largest + found in the matrix.
         */
        static int findLargestPlusPattern(int[][] arr, int symbol) {
            if (!isValid(arr)) {
                throw new IllegalArgumentException("Cannot perform search on empty array");
            }
            int maxPlusRadius = 0;
    
            int rows = arr.length;
            int cols = arr[0].length;
            int min = rows < cols ? rows : cols;
            int diff = rows > cols ? rows - cols : cols - rows;
    
            // Initializing initial window params. The center most smallest window possible
            // Example - For matrix of size {4x3}, smallest central window lies from [1][1] to [2][1]
            // Example - For matrix of size {3x9}, smallest central window lies from [1][1] to [1][7]
            int first_r, first_c, last_r, last_c;
            first_r = (min - 1) / 2;
            first_c = (min - 1) / 2;
            last_r = rows < cols ? (rows / 2) : (cols / 2) + diff;
            last_c = rows > cols ? (cols / 2) : (rows / 2) + diff;
    
            // Initializing with biggest possible search radius in the matrix
            int searchRadius = (min - 1) / 2;
    
            int r, c;
            int found;
    
            // Iteratively searching for + in an 'onion layer pattern' from inside to outside
            while (searchRadius > maxPlusRadius) {     // no need to find smaller + patterns than the one already found
                // initializing r and c cursor for this window iterations.
                r = first_r;
                c = first_c;
    
                // Search each of the 4 sides of the current window in a clockwise manner
                // 1# Scan the top line of window
                do { // do-while used to search inside initial window with width==1
                    found = findLargestPlusAt(r, c, arr, symbol, searchRadius);
                    if (found == searchRadius) {
                        return searchRadius;      // cannot find a bigger plus(+) than this in remaining matrix
                    } else if (found > maxPlusRadius) {
                        maxPlusRadius = found;
                    }
                    c++;
                } while (c < last_c);
                if (c > last_c)
                    c--; // for initial window with width==1. Otherwise #3 condition will be true for invalid c-index
    
                // 2# Scan the right line of window
                do {  // do-while used to search inside initial window with height==1
                    found = findLargestPlusAt(r, c, arr, symbol, searchRadius);
                    if (found == searchRadius) {
                        return searchRadius;
                    } else if (found > maxPlusRadius) {
                        maxPlusRadius = found;
                    }
                    r++;
                } while (r < last_r);
                if (r > last_r)
                    r--; // for initial window with height==1. Otherwise #4 condition will be true for invalid r-index
    
                // 3# Scan the bottom line of window
                while (c > first_c) {
                    found = findLargestPlusAt(r, c, arr, symbol, searchRadius);
                    if (found == searchRadius) {
                        return searchRadius;
                    } else if (found > maxPlusRadius) {
                        maxPlusRadius = found;
                    }
                    c--;
                }
    
                // 4# Scan the left line of window
                while (r > first_r) {
                    found = findLargestPlusAt(r, c, arr, symbol, searchRadius);
                    if (found == searchRadius) {
                        return searchRadius;
                    } else if (found > maxPlusRadius) {
                        maxPlusRadius = found;
                    }
                    r--;
                }
                // r and c comes back at first_r and first_c.
    
                // increasing window on all sides by 1.
                first_r--;
                first_c--;
                last_r++;
                last_c++;
    
                // reducing search radius to avoid out of bounds error on next window.
                searchRadius--;
            }
            return maxPlusRadius;
        }
    
        /**
         * Finds, if exist, the size of largest plus around a given point a[r][c]. It grows radius
         * greedily to maximise the search for + pattern returns 0 if is the point is the only symbol.
         *
         * @param r          row coordinate of search center
         * @param c          column coordinate of search center
         * @param a          matrix
         * @param symbol     search symbol
         * @param max_radius around the center to be searched for + pattern
         * @return returns -1 if the point itself is not the symbol.
         * returns n if all the next elements in E W N S directions within radius n are the symbol elements.
         */
        static int findLargestPlusAt(int r, int c, int[][] a, int symbol, int max_radius) {
            int largest = -1;
    
            if (a[r][c] != symbol) {   // If center coordinate itself is not the symbol
                return largest;
            } else {
                largest = 0;
            }
            for (int rad = 1; rad <= max_radius; rad++) {
                if (a[r + rad][c] == symbol && a[r][c + rad] == symbol && a[r - rad][c] == symbol && a[r][c - rad] == symbol) {
                    largest = rad;   // At least a '+' of radius 'rad' is present.
                } else {
                    break;
                }
            }
            return largest;
        }
    
        public static void main(String[] args) {
            int mat[][];
            mat = new int[][]{      // max + = 3
                    {1, 1, 0, 1, 1, 0, 1,},
                    {1, 1, 0, 1, 1, 0, 1,},
                    {1, 1, 0, 1, 1, 0, 1,},
                    {1, 1, 1, 1, 1, 1, 1,},
                    {1, 1, 0, 1, 1, 0, 1,},
                    {1, 1, 0, 1, 1, 0, 1,},
                    {1, 1, 0, 1, 1, 0, 1,},
            };
            int find = findLargestPlusPattern(mat, 1);
            System.out.println("# Max + size radius is : " + find);
            mat = new int[][]{  // max + = 2
                    {1, 1, 9, 1, 1, 9, 1,},
                    {1, 1, 9, 1, 1, 9, 1,},
                    {7, 1, 1, 1, 1, 1, 1,},
                    {1, 1, 9, 1, 1, 9, 1,},
                    {1, 1, 9, 1, 1, 9, 1,},
            };
            find = findLargestPlusPattern(mat, 1);
            System.out.println("# Max + size radius is : " + find);
    
            mat = new int[][]{      // max + = 1
                    {1, 1, 0, 1, 1},
                    {1, 1, 0, 1, 1},
                    {1, 1, 0, 1, 1},
                    {1, 1, 1, 6, 1},
                    {1, 1, 0, 1, 1},
                    {1, 1, 0, 1, 1},
            };
            find = findLargestPlusPattern(mat, 1);
            System.out.println("# Max + size radius is : " + find);
        }
    }