1. 程式人生 > 實用技巧 >ARTS習慣(4)

ARTS習慣(4)

目錄

米羅說

  • 幹難事必有所得

  • 捨近求遠,不珍惜身邊已有的做法是愚蠢的

  • 光說不練,假把式;光練不說,傻把式

Algorithm

每週至少做一個Leetcode演算法題

【題目來源】

求最大子矩陣大小,左程雲《程式設計師程式碼面試指南:IT名企演算法與資料結構題目最優解(第2版)》

【題目】

給定一個整型矩陣map,其中的值只有0和1兩種,求其中全是1的所有矩形區域中,最大的矩形區域為1的數量。

【例子】

// 全是1的最大矩形包含3個1
1 1 1 0
    
// 矩陣1 ,全是1的最大矩形有6個1
1 0 1 1
1 1 1 1
1 1 1 0

【解答】

步驟1:建立height陣列。我們以【例子】的矩陣1為例,height陣列表示:逐行切割矩陣,以切割的行做為底,統計每列的連續1的個數。切割矩陣第一行時,height = {1,0,1,1},切割矩陣第二行時,height = {2,1,2,2,2},切割矩陣第三行時,height = {3,2,3,0}

步驟2:單調棧求每列最大能左右擴多大。 以height = {3,4,5,4,3,6}為例說明,

1.生成棧stack存放height陣列的索引位置,從左至右遍歷height陣列

2.棧的壓入規則:棧單調遞減,遍歷到當前值height[i]時,height[i]>height[stack.peek()]

3.棧的彈出規則:height[i]<=height[stack.peek()]時,彈出棧頂位置,直到滿足壓入規則,即height[i]>height[stack.peek()]

4.最大矩形:j位置的最大矩形為(i-k-1)*height[j],注:j:當前彈出的棧頂位置,i:當前位置,k:彈出棧頂j後,新的棧頂。證明見求最大子矩陣大小

參考程式碼如下:

package com.pengluo.zcy_algorithm;

import java.util.Stack;

public class A16_MaxRecSize {

    public static int maxRecSize(int[][] map) {
        if (map == null || map[0].length ==0 || map.length == 0) {
            return 0;
        }
        int[] height = new int[map[0].length];
        int maxSize = 0;
        for (int i = 0; i < map.length; i++) {
            for (int j = 0; j < map[0].length; j++) {
                height[j] = map[i][j] == 0 ? 0 : height[j] + 1;
            }
            // 逐行切割,重新整理最大值
            maxSize = Math.max(maxRecFromBottom(height), maxSize);
        }
        return maxSize;
    }

    public static int maxRecFromBottom(int[] height) {
        if (height.length == 0 || height ==null){
            return 0;
        }
        int maxArea = 0;
        Stack<Integer> stack = new Stack<Integer>();
        for (int i = 0; i < height.length; i++) {
            while(!stack.isEmpty() && height[stack.peek()]>height[i]) {
                int j = stack.pop();
                int k = stack.isEmpty() ? -1 : stack.peek();
                int curArea = (i - k - 1 ) * height[j];
                maxArea = Math.max(curArea, maxArea);
            }
            stack.push(i);
        }
        
        while(!stack.isEmpty()) {
            int j = stack.pop();
            int k = stack.isEmpty() ? -1 : stack.peek();
            int curArea = (height.length - k - 1) * height[j];
        }

        return maxArea;
    }

    public static void main(String[] args) {
        int[][] map = {{1,0,1,1},{1,1,1,1},{1,1,1,0}};
        System.out.println(maxRecSize(map));


    }


}

【思考討論】

  • 思考公式(i-k-1)*height[j]的推導

Review

閱讀並點評至少1篇英文技術文章

【原文】:Head First Java(2nd Editon)CH8 Serious Polymorphism

【譯文】:英文版原汁原味,語義準確,本書的寫作風格幽默,容易理解。讀者應重點關注作者是如何一步一步帶你帶你分析問題的,不必糾結細枝末節的東西。讀者也可移步Head First Java(第二版·中文版)

【點評】:

多型主題圍繞:繼承父類實現介面展開,看完本章後豁然開朗,一些模稜兩可的概念一下就清晰了。

  • The compiler won’t let you instantiate an abstract class(抽象類不能例項化)

  • An abstract method has no body! (抽象方法沒有{},分號結尾,需要在具體類中override)

    abstract public class Dog {
        abstract public void eat();
    }
    
  • Every class in Java extends class Object(Java中任何類直接或間接的都繼承Object)

  • multiple inheritance has Deadly Diamond of Death(Java不允許多繼承,死亡菱形)

  • A Java interface is like a 100% pure abstract class.(介面是百分百的抽象類,Java允許實現多個介面)

  • Polymorphism(多型)

    • 多使用抽象的父類做方法引數、返回型別、陣列 賦值

      abstract public class Animal {}
      public Dog extends Animal {}
      public Cat extends Animal {}
      
      // 陣列
      Animal[] animals = new Animal[3];
      animals[0] = new Dog();
      animals[1] = new Cat();
      
      // 方法入參
      public void add(Animal a)    {
          
      }
      
    • 強轉型別之前,instanceof 判斷型別

      if (d instanceof Dog) {
          Dog dog = (Dog) 
      }
      
  • 2個常見介面

// save state to a file
public class Dog implements Serializable

// run its method in a separate thread of execution 
public class Dog implements Runnable

Tip

學習至少一個技術技巧

參考我之前寫的一篇Mybatis逆向工程生成程式碼的部落格。自動化配置(1):利用Mybatis-generator自動生成實體類,介面,mapper.xml

Share

分享一篇有觀點和思考的技術文章

分享極客時間上的一個演算法專欄,谷歌演算法工程師主講的,資料結構和演算法之美

目前已突破10W訂閱,乾貨很多,能堅持跟下來會很有收穫的。