xxleyi / loop_invariants

记录以及整理「循环不变式」视角下的算法题解

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

leetcode 682. 棒球比赛

xxleyi opened this issue · comments

题:

你现在是棒球比赛记录员。
给定一个字符串列表,每个字符串可以是以下四种类型之一:
1.整数(一轮的得分):直接表示您在本轮中获得的积分数。
2. "+"(一轮的得分):表示本轮获得的得分是前两轮有效 回合得分的总和。
3. "D"(一轮的得分):表示本轮获得的得分是前一轮有效 回合得分的两倍。
4. "C"(一个操作,这不是一个回合的分数):表示您获得的最后一个有效 回合的分数是无效的,应该被移除。

每一轮的操作都是永久性的,可能会对前一轮和后一轮产生影响。
你需要返回你在所有回合中得分的总和。

示例 1:

输入: ["5","2","C","D","+"]
输出: 30
解释: 
第1轮:你可以得到5分。总和是:5。
第2轮:你可以得到2分。总和是:7。
操作1:第2轮的数据无效。总和是:5。
第3轮:你可以得到10分(第2轮的数据已被删除)。总数是:15。
第4轮:你可以得到5 + 10 = 15分。总数是:30。

示例 2:

输入: ["5","-2","4","C","D","9","+","+"]
输出: 27
解释: 
第1轮:你可以得到5分。总和是:5。
第2轮:你可以得到-2分。总数是:3。
第3轮:你可以得到4分。总和是:7。
操作1:第3轮的数据无效。总数是:3。
第4轮:你可以得到-4分(第三轮的数据已被删除)。总和是:-1。
第5轮:你可以得到9分。总数是:8。
第6轮:你可以得到-4 + 9 = 5分。总数是13。
第7轮:你可以得到9 + 5 = 14分。总数是27。

注意:

    • 输入列表的大小将介于1和1000之间。
    • 列表中的每个整数都将介于-30000和30000之间。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/baseball-game
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


解:按照题意手搓几个回合,应该能感受到「栈」的感觉。

此题的「循环不变式」就是在循环过程中,对「栈」进行正确操作,同时正确更新此时的总分。

// 构造一个简单的栈,包含 push, pop, top 操作
function Stack() {
  this.v = []
}

Stack.prototype.top = function() {
  return this.v[this.v.length - 1]
}

Stack.prototype.push = function(e) {
  this.v.push(e)
}

Stack.prototype.pop = function() {
  return this.v.pop()
}

var calPoints = function(ops) {
  const points = new Stack()
  let total = 0

  const switchDo = {
    '+': () => {
      const [p1, p2] = [points.pop(), points.pop()]
      points.push(p2)
      points.push(p1)
      points.push(p1 + p2)
    },
    'D': () => points.push(points.top() * 2),
    'C': () => total -= points.pop(),
  }

  const defaultDo = (e) => points.push(parseInt(e))

  const dispatch = (e) => {
    if (e in switchDo) switchDo[e]()
    else defaultDo(e)
  }

  for (const e of ops) {
    // do what should do
    dispatch(e)
    // increase total if we should
    if (e !== 'C') total += points.top()
  }

  return total
};