手写算法: 买卖股票的最佳时机 II

122. 买卖股票的最佳时机 IIopen in new window

解法一:贪心算法

只算正利润,用当天

var maxProfit = function(prices) {
  let result = 0;
  for (let i = 1; i < prices.length; i++) {
    result += Math.max(prices[i] - prices[i - 1], 0);
  }
  return result;
};

解法二:动态规划

买卖股票的最佳时机思路一样,只是这道题股票可以买卖多次。

那么在计算 dp[i][0]的时候,需要用昨天不持有股票现金 - 今天的股票价格,即dp[i - 1][1] - prices[i]。因为目前不持有股票现金包括之前卖出赚的利润。

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
  const len = prices.length;
  let dp = new Array(len).fill([0, 0]);
  dp[0] = [0, -prices[0]];
  console.log(dp);

  for (let i = 1; i < len; i++) {
    dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);
    dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] - prices[i]);
  }
  return dp[len - 1][0];
};

手写题

手写 JSON.parse()

22. 手写 JSON.parse()open in new window

/**
 * @param {string} str
 * @return {object | Array | string | number | boolean | null}
 */
function parse(str) {
  const json = eval('(' + str + ')');

  if (JSON.stringify(json) === str) {
    return json;
  }
  throw new Error(str);
}

JS 简答题

Hoisting III

29. Hoisting IIIopen in new window

var a = 1;

function func() {
  a = 2;
  console.log(a);
  var a;
}

func();

console.log(a);

if (!('b' in window)) {
  var b = 1;
}

console.log(b);

解析

看到if {}块就要主要,变量提升问题!!!不要忘记了

// b 变量会被提升,b此时已被定义,暂未赋值
if (false) {
  var b;
}
// true, 变量被提升,已经在window作用域下
'b' in windows;

instanceOf

15. instanceOfopen in new window

console.log(typeof null);
console.log(null instanceof Object);
console.log(typeof 1);
console.log(1 instanceof Number);
console.log(1 instanceof Object);
console.log(Number(1) instanceof Object);
console.log(new Number(1) instanceof Object);
console.log(typeof true);
console.log(true instanceof Boolean);
console.log(true instanceof Object);
console.log(Boolean(true) instanceof Object);
console.log(new Boolean(true) instanceof Object);
console.log([] instanceof Array);
console.log([] instanceof Object);
console.log((() => {}) instanceof Object);

解析

基础类型都没有instanceof关键字

console.log(typeof null); // "object" - 'null' has "object" type in js (backward compatibility)

console.log(null instanceof Object); // false - 'null' is primitive and doesn't have 'instanceof' keyword

console.log(typeof 1); // "number" - one of js types

console.log(1 instanceof Number); // false - '1' is primitive and doesn't have 'instanceof' keyword

console.log(1 instanceof Object); // false - same as above

console.log(Number(1) instanceof Object); // false - Number(1) === 1 - same as above

console.log(new Number(1) instanceof Object); // true - 'new Number(1)' is object, so it's correct

console.log(typeof true); // "boolean" - one of js types

console.log(true instanceof Boolean); // false - 'true' is primitive and doesn't have 'instanceof' keyword

console.log(true instanceof Object); // false - same as above

console.log(Boolean(true) instanceof Object); // false - Boolean(true) === true - same as above

console.log(new Boolean(true) instanceof Object); // true - 'new Boolean(true)' is object, so it's correct;

console.log([] instanceof Array); // true - '[]' is instanceof Array and Object

console.log([] instanceof Object); // true - '[]' is instanceof Array and Object

console.log((() => {}) instanceof Object); // true - if it's not a primitive it's object. So callback is instanceof object

Implicit Coercion I

8. Implicit Coercion Iopen in new window

console.log(Boolean('false'));
console.log(Boolean(false));
console.log('3' + 1);
console.log('3' - 1);
console.log('3' - ' 02 ');
console.log('3' * ' 02 ');
console.log(Number('1'));
console.log(Number('number'));
console.log(Number(null));
console.log(Number(false));

解析

  • false, '0', [],这三个在强制转换成数字的时候会成 0

  • 减法、乘法,遇到字符串时会先转换成数字类型,再进行计算

  • Number(value),如果入参无法转换成数字,则返回 NaN

true or false

26. true or falseopen in new window

console.log([] == 0);
console.log([] == false);
console.log(!![]);
console.log([1] == 1);
console.log(!![1]);
console.log(Boolean([]));
console.log(Boolean(new Boolean([])));
console.log(Boolean(new Boolean(false)));

解析

  1. == 与 Boolean()规则不一致, Boolean() 与 ! 规则一致

  2. Boolean()中,如果值为0, -0, NaN, null, undefined, false, ''(空字符串),都似为 false。其他的值都为 true

console.log(!![]); // !(!true) ==> !false ==> true
console.log([1] == 1); // [1] == 1 ==> 1 == 1 ==> true
console.log(Boolean([])); // Boolean(true) ==> true
console.log(Boolean(new Boolean([]))); // new Boolean([]) ==> 输入出对象为true Boolean(any object) will be true

NaN

92. NaNopen in new window

mdn JavaScript 中的相等性判断open in new window

console.log(NaN == NaN);
console.log(NaN === NaN);
console.log(Object.is(NaN, NaN));
console.log([NaN].indexOf(NaN));
console.log([NaN].includes(NaN));
console.log(Math.max(NaN, 1));
console.log(Math.min(NaN, 1));
console.log(Math.min(NaN, Infinity));

解析

  • Array.prototype.includes(),怀疑底层是用 object.is()判断的, 此题返回 true

  • Math.max(), Math.min(),入参中至少有一个参数无法转换成数字,那么就会返回 NaN

this

19. thisopen in new window

const obj = {
  a: 1,
  b: function() {
    console.log(this.a);
  },
  c() {
    console.log(this.a);
  },
  d: () => {
    console.log(this.a);
  },
  e: (function() {
    return () => {
      console.log(this.a);
    };
  })(),
  f: function() {
    return () => {
      console.log(this.a);
    };
  },
};

console.log(obj.a)
obj.b()
;(obj.b)()
const b = obj.b
b()
obj.b.apply({a: 2})
obj.c()
obj.d()
;(obj.d)()
obj.d.apply({a:2})
obj.e()
;(obj.e)()
obj.e.call({a:2})
obj.f()()
;(obj.f())()
obj.f().call({a:2})

解析

obj.f 是一个普通函数,它返回形成闭包并记住外部函数作用域的箭头函数。

  • 普通函数,this 的值取决于函数的调用方式,即运行时绑定

  • 箭头函数,不提供 this 绑定,它保留封闭词法上下文的 this,即静态绑定

  • call()、apply() 更改作用域,使用给定的 this 值调用函数。箭头函数不能用 call、apply,因为它没有 this

null and undefined

9. null and undefinedopen in new window

console.log(JSON.stringify([1, 2, null, 3]));
console.log(JSON.stringify([1, 2, undefined, 3]));
console.log(null === undefined);
console.log(null == undefined);
console.log(null == 0);
console.log(null < 0);
console.log(null > 0);
console.log(null <= 0);
console.log(null >= 0);
console.log(undefined == 0);
console.log(undefined < 0);
console.log(undefined > 0);
console.log(undefined <= 0);
console.log(undefined >= 0);

解析

  • JSON 没有undefined的值,它在 JSON 数据类型中被替换成null

  • ==运用于nullundefined时,不会发生数字转换。null 只等于 null 或 undefined

  • 做运算计算时,null, undefined转换成数字时,null会变成 0, 而undefined会变成 NaN

null == null; // true
null == undefined; // true

null === null; // true
null === undefined; // false

null == 0; // false,== 运算符时,只跟undefined相等
null < 0; // false, 做运算时,null会先变成0再进行比较,0 < 0

undefined == 0; // false, undefined转成数字再进行比较,NaN == 0

Proxy I

80. Proxy Iopen in new window

const obj = new Map();
const map = new Map();
obj.foo = 1;
map.set('foo', 2);
console.log(obj.foo);
console.log(map.get('foo'));

const proxyObj = new Proxy(obj, {});
const proxyMap = new Proxy(map, {});
console.log(proxyObj.foo);
console.log(proxyMap.get('foo'));

解析

Many built-in objects, for example, Map, Set, Date, Promise and others make use of so-called internal slots. These are like properties but reserved for internal, specification-only purposes. For instance, Map stores items in the internal slot [[MapData]]. Built-in methods access them directly, not via [[Get]]/[[Set]] internal methods. So Proxy can’t intercept that. e.g.

let map = new Map();
let proxy = new Proxy(map, {});
proxy.set('name', 'kk'); // Error

proxy 代理后无法用 get、set 拦截

Increment Operator

7. Increment Operatoropen in new window

let a = 1;
const b = ++a;
const c = a++;
console.log(a);
console.log(b);
console.log(c);

解析

let a = 1;
// ++a,先加再赋值,所以此时b为2
const b = ++a;

// 但是由于a是let属性,所以a要更新, 此时a也为2
console.log(a);

// a++, 是先赋值后加,所以此时b为2
const c = a++;

// 赋值完后,a++, a变为3
console.log(a);
Last Updated:
Contributors: kk