Skip to content

Latest commit

 

History

History
129 lines (98 loc) · 6.05 KB

张凯-20180730.md

File metadata and controls

129 lines (98 loc) · 6.05 KB

leetcode

问题:Cherry Pickup

解答:

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

// 关键是把题目转化成:
// 同时两个人从(0,0) -> (n-1,n-1)
// 另外,行数和列数定义后,可以走的次数是固定。例如,现在有r行, l列,那么最多可以走的次数是r+l-1
//
// 记行数为r,列数为l,当前走的步数为t,1<=t<=r+l-1
//
// 观察到,一个人现在的位置是(x, y),已经走了t步,那么x+y=t+1。因此,两个人移动的时候可以记录状态
// c[t][x1][x2]表示两个人移动了t步,同时的位置分别是(x1, -tx1+1),(x2, -tx2+1)捡到的最多的樱桃数
//
// 状态转移函数:
// 1. c[t][x1][x2] = -1 if grid[x1][t-x1+1] == -1 || grid[x2][t-x2+1] == -1
// 任何一个人所在的位置是无法通过的,那么这个状态下的樱桃数就是不可能存在的,用-1标记
//
// 2. c[t][x1][x2] = grid[x1][t-x1+1] + (x1 == x2 ? 0 : grid[x2][t-x2+1]) +
// max(c[t-1][x1][x2],c[t-1][x1-1][x2],c[t-1][x1][x2-1],c[t-1][x1-1][x2-1])
// grid[x1][t-x1+1] 表示第一个人所在的位置樱桃的数量
// x1 == x2 判断的目的是避免重复计算,因为这个时候两个人站在同一个位置上面
// c[t-1][x1][x2] 两个人都往下走
// c[t-1][x1-1][x2] 第一个人往右走,第二个人往下走
// c[t-1][x1][x2-1] 第一个人往下走,第二个人往右走
// c[t-1][x1-1][x2-1] 两个人都往右走


int cherryPickup(int** grid, int gridRowSize, int gridColSize) {
  int c[2][51][51], cc, n, p, mi, mj, m, i, j;
  int t = 1, l = gridRowSize + gridColSize, xi, yi, xj, yj;
  for (i = 0; i <= gridRowSize; i++) {
    for (j = 0; j <= gridColSize; j++) {
      c[0][i][j] = -1;
      c[1][i][j] = -1;
    }
  }

  c[(t-1)&1][1][1] = grid[0][0] == -1 ? -1: 0; // for simplify the logic
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))

  for (; t < l; t++) {
    for (xi = 1, mi = min(gridRowSize + 1, t + 1); xi < mi; xi++) {
      yi = t - xi + 1;
      if (yi > gridColSize) continue;
      i = grid[xi-1][yi-1];

      for (xj = 1, mj = min(gridColSize + 1, t + 1); xj < mj; xj++) {
        yj = t - xj + 1;
        if (yj > gridColSize) continue;
        j = grid[xj-1][yj-1];

        n = t & 1;
        if (i == -1 || j == -1) {
          c[n][xi][xj] = -1;
          continue;
        }

        cc = i;
        if (xi != xj) {
          cc += j;
        }

        cc += m;
        c[n][xi][xj] = cc;
      }
    }
  }

  m =  max(c[(t-1)&1][gridRowSize][gridColSize], 0);
#undef max
#undef min

  return m;
}

英文技术文章

文章:https://medium.com/@rdsubhas/10-modern-software-engineering-mistakes-bc67fbef4fc8

内容

例举10种软件过度工程化的问题。

  1. 过度预期业务需求。事实是业务的变化总为超乎你的估计,因此专注眼前的设计。
  2. 重用业务功能。事实是因为业务逻辑的易变性,使得重用部分变得越来越臃肿,本质是业务逻辑之间的耦合,解耦之后,公用部分就会变成薄薄的一层。
  3. 过度通用化(抽象化)。事实是当你刚刚抽象完以后,需求又变了,过度抽象也是有问题的。
  4. 浅封装。封装一切外部库。事实是很多库质量已经很高,另外封装和库紧密结合,库的修改一样会导致代码修改,有时候封装倒是多余。
  5. 盲目使用代码质量规则。事实是10行完成的hello,world,通过使用SOILD花了100多行代码。需要了解每个原则解决的问题。
  6. 为技术而技术。泛型很酷,来个HelloWorldPrinter<String, Writer>;策略模式很巧,见到if就用它来替换。
  7. 过度最求可配置性、安全性、扩展性、可维护性。单从一个点上看都没毛病,关键是它解决了你的问题了吗,如果跟你的问题关系不大,那就是把力气花错地方了。
  8. 闭门造车。一个好用的库需要深刻理解业务领域知识,同时需要花费时间去维护。所以,在使用开源方案和自己开发一个之间需要做权衡。
  9. 对老代码保持沉默。坚持重构,没有代码是不可以改的,目的是为了保持代码代码干净,可维护,可扩展。(稳定的代码谁愿意改哦)
  10. 高估自己的能力。软件高质量除了技能,还需要时间。事实是能力很强的团队搞出了不怎么的玩意。

软件工程,问题导向,一切都是为了需要解决的问题;学的越多,感觉越没有一种固定的方法,一切都是你能hold住为前提。

学习新的技术技巧

less命令中,通过xxg跳转到xx行,如果没有xx默认跳到第一行,对应的还有G,除了默认跳到最后一行,其他和g一样。

分享文章

接口分离原则

又名ISP(Interface Segregation Principles)。使用者不应该依赖它不使用的方法。所以,分离的使用者意味着分离的接口。

当你依赖的接口包含不需要的方法时,加上依赖的传递性,从源代码角度看当接口的改变,你的代码可能会跟着改变(这是因为对动态语言来说不用修改原来的代码),从架构角度看由于组件依赖,当组件修改时,会导致组件的重新编译、发布。ISP的目的还是减少类、模块间的耦合,提供类、模块的内聚性,提高代码的可扩展性、可复用性。

有两类接口:

  1. class interface,在类层面履行接口,每个实现细节实现具体的接口,在golang中就是interface定义的接口。
  2. object interface,在对象层面履行接口,每个新建的对象拥有类的方法,在golang中就是struct定义的方法。

SRP也强调职责分离,虽然它的效果也会有ISP的效果,但是它是从业务逻辑的角度去归类职责并进行分离。而ISP是从接口的角度去分离接口,它是在SIP的基础上进一步的细分。

几个比较好的实践:

  1. 一个接口是只服务于一个模块或者业务逻辑。
  2. 尽量减少公共的方法。
  3. 保持接口的干净。如果有污染尽快修复。