ARTS-WEEK 7

Posted by Eric Jin on 2019-04-04

Algorithm

Description

Given a 2D integer matrix M representing the gray scale of an image, you need to design a smoother to make the gray scale of each cell becomes the average gray scale (rounding down) of all the 8 surrounding cells and itself. If a cell has less than 8 surrounding cells, then use as many as you can.

Example 1:

Input:
[[1,1,1],
 [1,0,1],
 [1,1,1]]
Output:
[[0, 0, 0],
 [0, 0, 0],
 [0, 0, 0]]
Explanation:
For the point (0,0), (0,2), (2,0), (2,2): floor(3/4) = floor(0.75) = 0
For the point (0,1), (1,0), (1,2), (2,1): floor(5/6) = floor(0.83333333) = 0
For the point (1,1): floor(8/9) = floor(0.88888889) = 0

Note:

  1. The value in the given matrix is in the range of [0, 255].
  2. The length and width of the given matrix are in the range of [1, 150].

solution

思路:遍历矩阵中的每一个元素,把周边的所有元素的和加起来放到一个跟矩阵一样的二维数组中去,加完以后,对元素之和求平均值。

    if (M == null)  return null;
    int xLen = M.length,yLen = M[0].length;
    int[][] smoothArray = new int[xLen][yLen];
    for (int i = 0; i < xLen; i++) {
        for (int j = 0; j < yLen; j++) {
            int cnt = 0;
            for (int inRow = i-1; inRow <= i+1 ; inRow++) {
                for (int inCol = j-1; inCol <= j+1 ; inCol++) {
                    if (inRow >= 0 && inRow < xLen && inCol >= 0 && inCol < yLen) {
                        smoothArray[i][j] += M[inRow][inCol];
                        cnt++;
                    }
                }
            }
            smoothArray[i][j] /= cnt;
        }
    }
    return smoothArray;

Review

读《Effective Java》–Item 28: Prefer list to arrays Array 和 泛型两个非常不同的点:

  1. array 是covariant, 意思是协变的。就是如果 SubSuper的子类,那么 数组 Sub[] 也是 数组 Super[]的子类。反过来是,泛型是invariant,不变的。两个不同的类型Type1Type2List<Type1> 既不是List<Type2> 的子类也不是超类。

    //运行时异常
    Object[] objectArray = new Long[1];
    objectArray[0] = "I don't fit in"; // Throws ArrayStoreException
    
    //编译异常
    List<Object> ol = new ArrayList<Long>(); //Incomatible type
    ol.add("I don't fit in");
    

    我们常说,错误要尽早出现,泛型在编译时就直接错误了。

  2. 第二个不同点是,arrayreified,具体化的。这意味着数组在运行时知道它元素的类型。所以你在运行时的时候,上面那个例子就会由于你往一个Long类型的数组中间放入了一个String, 所以就得到了一个ArrayStoreException。而泛型的实现是由于erasure, 擦除。这意味着它只在编译时知道它的类型,在运行时就会丢失它的元素信息。Erasure就是泛型能够非常好的兼容古老代码的原因,可以让Java 5以前的代码平滑过渡。

因为这两点的不同,所以数组和泛型没办法很好的结合在一起。

new List<E>[],new List<String>[],new E[] 像这些创建数组的语句都是不合法的,都会有编译异常。

Tip

new ArrayList<>(Arrays.asList()) 和 Arrays.asList() 的区别

public static void main(String[] args) {
    Random rand = new Random(47);
    Integer[] ia = {1, 2, 3, 4, 5, 6, 7, 8, 9};
    List<Integer> list1 = new ArrayList<>(Arrays.asList(ia));
    System.out.println("before" + list1);
    Collections.shuffle(list1);
    System.out.println("aftere" + list1);
    System.out.println("array" + Arrays.toString(ia));
    System.out.println("===========");
    List<Integer> list2 = Arrays.asList(ia);
    Object[] list3 = list2.toArray();
    System.out.println("before" + list2);
    Collections.shuffle(list2);
    System.out.println("after" + list2);
    System.out.println("array" + Arrays.toString(ia));
}

当我们在对list1 进行操作的时候,Arrays.asList() 是被放在了 ArrayList() 的构造方法下面,构造方法会调用toArray() 方法。看ArrayList构造方法和 Arrays.ArrayList 的源码

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
private static class ArrayList<E> extends AbstractList<E>
    implements RandomAccess, java.io.Serializable
{
    private static final long serialVersionUID = -2764017481108945198L;
    private final E[] a;

    ArrayList(E[] array) {
        a = Objects.requireNonNull(array);
    }

    @Override
    public Object[] toArray() {
        return a.clone();
    }
}

所以,直接操作 Arrays.List(),你会更改最原始的那个数组,但是如果你操作的是 new ArrayList<>(Arrays.asList()), 操作的只是数组的一个clone,不会操作原有的数组。

Share

最近一直要登录我自己的VPS, 以前是用的secureCRT, 所以还没有觉得有什么不方便。但是最近用上ubuntu了,可以直接用系统终端,不需要secureCRT或者xshell之类的软件了,这个时候登录VPS的时候就感觉比较麻烦了,每次都需要用ssh命令,而且还需要把密码找出来输入。

多方寻找,找到了expect的工具。首先可以直接用teminal 输入 apt-get install expect, 还是不要用snap install expect,因为我用这个snap 安装的 expect 在执行 spawn ssh user@host 的时候总是permission denied。 所以就卸载用apt-get 进行安装,会安装到 /usr/bin/expect 下面。

好了,先铺代码:

#!/usr/bin/expect  
set timeout 3
set user "[user]"
set host "[host]"	
set pwd "[password]"	//自己的VPS服务器ip和密码


proc func_login {password} {
    expect {
        "*(yes/no)? " {
            send "yes\r";
            exp_continue
        }
        "*password*" {
            send "$password\r";
            exp_continue
        }
        "*]\$ " {
            #send_log "\r>>>>>>>>>> Login in SUCCESS <<<<<<<<<<<<\r";
            puts "\r>>>>>>>>>> Login in SUCCESS <<<<<<<<<<<<\r"
        }
        "Permission denied*" {
            send_error "\r>>>>>>>>>> Login in FAILED <<<<<<<<<<<<\r";
            close;
            exit
        }
    }
}

spawn ssh $user@$host 
func_login $pwd 
interact

简单解释:

  • spawn 命令会激活一个进程来进行交互式的程序运行

  • send 会向进程发送字符串

  • expect 会等待进程的一些字符串,可以用正则匹配。也可以同时等待多个字符串,并对每一个字符串执行不同的操作。expect还能理解一些特殊情况,如超时和遇到文件尾。所以我们在前面设置了3秒的超时。

  • interact 命令最后把进程移交给用户进行交互。如果这段代码没有interact ,执行完登录后,你就会看到它又自己退出了。

    expect教程中文版