leetcode-棒球比赛

说明:

你现在是棒球比赛记录员。
给定一个字符串列表,每个字符串可以是以下四种类型之一:
1.整数(一轮的得分):直接表示您在本轮中获得的积分数。

  1. “+”(一轮的得分):表示本轮获得的得分是前两轮有效 回合得分的总和。
  2. “D”(一轮的得分):表示本轮获得的得分是前一轮有效 回合得分的两倍。
  3. “C”(一个操作,这不是一个回合的分数):表示您获得的最后一个有效 回合的分数是无效的,应该被移除。

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

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

解决思路:模拟栈

public function solution($ops)
    {
        $stack = [];
        $res = 0;
        foreach ($ops as $k=>$op) {
            switch ($op) {
                case "+":
                    count($stack) > 1 ? $end = end($stack) + $stack[count($stack)-2] : $end = end($stack);
                    array_push($stack, (int)$end);
                    $res += end($stack);
                    break;
                case "D":
                    array_push($stack, (int)(end($stack)*2));
                    $res += end($stack);
                    break;
                case "C":
                    $res -= array_pop($stack);
                    break;
                default:
                    array_push($stack, (int)$op);
                    $res += end($stack);
                    break;
            }
        }
        return $res;
    }
Visits: 889

leetcode-一周中的第几天

如何不使用自带的公式自己造轮子获取一周的星期几呢,可以使用吉姆拉森日期计算公式。

public function __construct()
    {
        $this->weeks = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    }

    /**
     * 基姆拉尔森日期公式
     * @param int $day
     * @param int $month
     * @param int $year
     * @return mixed
     */
    public function solution(int $day, int $month, int $year)
    {
        return $this->weeks[($day + 2*$month + 3*($month+1)/5 + $year + $year/4 - $year/100 + $year/400) % 7];
    }
Visits: 46

使用虚拟列减少索引的扫描行数

假设现在有一张表记录了每个人的基本信息

create TABLE `t_people` (
  `id` INT(11) DEFAULT NULL ,
  `name` VARCHAR(20) DEFAULT NULL ,
  `age` INT(11) DEFAULT NULL ,
  `info` VARCHAR(255) DEFAULT NULL
)ENGINE = InnoDB;

里面总共有三条数据

INSERT INTO test.t_people (id, name, age, info, name_fist) VALUES (1, '张三', 8, null, '张');
INSERT INTO test.t_people (id, name, age, info, name_fist) VALUES (2, '李四', 12, null, '李');
INSERT INTO test.t_people (id, name, age, info, name_fist) VALUES (3, '张三', 11, null, '张');

现在我们需要找出姓名开头是张且年龄等于8的数据。

一、我们很容易想到给表添加名字和年龄的联合索引。

ALTER TABLE t_people ADD INDEX name_age_index(name, age);

搜索语句:

EXPLAIN SELECT * FROM t_people WHERE name LIKE '张%' AND age=8;

执行结果如下,总共扫描了2行

二、使用虚拟列

ALTER TABLE t_people add name_fist VARCHAR(2) GENERATED ALWAYS
as (left(name,1)),ADD INDEX name_fist_age_index(name_fist, age);

语句如下:

EXPLAIN SELECT * FROM t_people WHERE name_fist='张' AND age=8;

执行结果如下,只扫描了1行

总结:

1.虚拟列在插入的时候不能指定值,更新的时候也不能主动修改,它的值会根据定义自动修改。

2.查询优化的过程往往就是较少扫描行数的过程。

Visits: 1765