Skip to content

Latest commit

 

History

History
134 lines (94 loc) · 5.33 KB

张凯-20180722.md

File metadata and controls

134 lines (94 loc) · 5.33 KB

leetcode

问题:Wildcard Matching

解答:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

//
// https://leetcode.com/problems/wildcard-matching/
//
// m[i, j] is the result of pattern end with p[i - 1] and string end with s[j - 1]
// if p[i - 1] == s[j - 1] or p[i - 1] = '?', m[i - 1][j - 1]
// if p[i - 1] = '*', m[i - 1][j] || m[i][j - 1] || m[i - 1][j - 1]
// else false


bool isMatch(char* s, char* p) {
  size_t sl = strlen(s), pl = strlen(p);
  bool **m = malloc((pl + 1) * sizeof (*m));
  for (size_t i = 0; i <= pl; i++) {
    m[i] = malloc((sl + 1) * sizeof (**m));
  }

  memset(m[0], false, sl);
  m[0][0] = true;

  for (size_t i = 1; i <= pl; i++) {
    for (size_t j = 0; j <= sl; j++) {
      bool ja = j > 0;
      if ((ja && p[i - 1] == s[j - 1]) || p[i - 1] == '?') {
        m[i][j] = m[i - 1][j - 1];
        continue;
      }

      if (p[i - 1] == '*') {
        m[i][j] = m[i - 1][j] || (ja ? m[i][j - 1] || m[i - 1][j - 1]: false);
        continue;
      }

      m[i][j] = false;
    }
  }

  return m[pl][sl];
}

英文技术文章

文章:https://medium.com/@benbjohnson/standard-package-layout-7cdbc8391fc1

内容

一种在golang开发应用的包组织方式。这样设计的理由:先设计领域语言,然后分离依赖,接着引入mock分离测试,最后在main包中把所有的东西拼接在一起。

主要有4条建议:

  1. 根包仅仅包含领域类型以及相关的接口定义
  2. 程序的每个依赖对应一个子包,比如基于mongdb实现
  3. 共享一个mock接口的子包
  4. main包把相关的依赖组合在一起

例如:

app/
	user.go
	mongodb/
	mock/
	http/
	cmd/
		app/
			main.go
		appctl/
			main.go
  1. 根包是appuser.go定义User类型以及相应的接口UserService
  2. UserService的mongodb实现,放在子包mongodb中,暴露的http接口放在http中。
  3. 子包mock中包含共享的一个mock的UserService,里面默认的都是一些空方法,被其他测试时引用。
  4. main这个包负责构建http实例、UseService实例把这些合在一起构成一个app。

学习新的技术技巧

meld用来做git的mergetool,做三方合并,可以一个开发人员把另一个开发人员的代码误删的情况。

分享文章

里氏替换原则

又名LSP(Liskov Substitutiion Principle)。基类能够被子类代替,并且保证程序行为不变。

OCP的实现需要使用抽象和多态,静态语言中继承是多态的一个重要实现方式。LSP就是解决继承带来的一些问题,比如侵入性、耦合性、缺乏灵活性。遵守LSP能够更加容易遵守OCP,因为子类可以替换基类,达到不修改原来代码,通过扩展的方式,添加逻辑。提高程序的健壮性,版本升级的兼容性。

继承中常说的IS-A,强调的是方法的行为,子类中的方法行为要和基类中的一致,而不是性质一致。这个行为需要从设计的使用者角度来判断模块。模块逻辑的一致性,说的就是这个行为需要一致。所以,IS-A语义是子类替换时,保证程序行为一致。

虽然这里LSP强调代码中的继承,其实LSP也适用于其他约定的服务、组件,这些内容修改、替换以后都不应该影响原来程序的行为。

几个比较好的实践:

  1. 当子类中override的方法工作比较少时,可能违反LSP。
  2. 采用DBC(design by contract)编程方法。约定方法的前置条件和后置条件,在LSP下,子类中的前置条件只能比基类的弱,而子类中的后置条件只能比基类的强。因为,如果子类中的前置条件强,那么替换以后原来基类的前置条件下的输入就没法满足了,同样如果子类的后置条件弱,那么方法的输出在一些情况下程序行为就会和原来的不一样。

依赖反转原则

又名DIP(Dependence Inversion Principle)。高层不依赖底层,依赖抽象,底层也只依赖抽象;抽象不依赖细节,细节依赖抽象。

反转(inversion)包含两层含义:

  1. 控制流和源代码依赖相反,a模块执行时会调用b模块函数,但是源代码层面来说b模块会依赖a模块。
  2. 接口所有者,原先a模块使用b模块定义的接口,而现在接口放在了a模块中,从而从源代码层面来说b模块依赖a模块。

为什么要依赖抽象?显然抽象比实现细节稳定。从编程语言角度上来说,接口变了实现不变,而实现变了,接口不一定变,显然接口更加稳定。因此,接口的稳定也十分重要。

DIP能够减少类、模块之间的耦合,提供系统的稳定性,提高代码的复用性、可扩展性、可读性和可维护性。它是其他OO设计技巧的基础。

建立依赖的方式:

  1. 构造函数传递依赖对象。
  2. setter方法传递对象。
  3. 接口声明依赖对象,接口中的方法参数、返回值中引用其他接口。

几个比较好的实践:

  1. 每个类尽量有接口或者抽象类。
  2. 变量的表面类型尽量是接口、抽象类型或者是不易变的类。
  3. 任何类不从易变的具体类派生。在维护代码的时候这个实践经常会被破坏。
  4. 尽量不要override基类的方法。
  5. 创建对象时考虑使用工厂模式。