什么鬼,我代码都没合并,他说他测完了。。。

文摘   2024-11-20 10:24   山西  

我最近看到一个贴子,直接把我整笑了。有人说:“我代码都没合并,测试说他测完了……”这话听着就离谱。

作为一名开发,看到这种场景真是又好气又好笑。测试提前踩点,这是想“先占个坑再说”?

但话说回来,这事其实不罕见。写代码的都懂,我们埋头改需求、修bug,测试却在那边标个“已完成”。要是没沟通清楚进度,最后出了问题,锅还不是甩到开发头上。

所以我觉得吧,开发和测试之间的信任和协作才是重中之重,不然总有人在“勇敢试探”和“被动背锅”之间游走。

今日算法题


好了,吃完瓜,我们说说算法题,最近刷题的时候,我碰到了一个题,叫“用 Read4 读取 N 个字符 II - 多次调用”。光看名字,就感觉像是在念舌绕题,但其实它并没有那么复杂,今天我就跟大家聊聊这道题。

先从基础讲起吧。题目给了我们一个 read4 方法,这个方法每次能从某个文件里读取最多 4 个字符。它的签名一般是这样的:

int read4(char[] buf4);

buf4 是一个长度为 4 的字符数组,用来存放读取的字符。如果文件中剩下的字符不足 4 个,那它会只读剩下的字符,返回读取的实际数量。

这题的核心是要实现一个新的 read 方法:

int read(char[] buf, int n);

它能让用户多次调用,逐步从文件中读取指定数量的字符。而这里的难点就在于,read4 是一次性读取 4 个字符的,我们得想办法把这些字符合理分配到多次调用中。

用大白话总结一下问题:我们手上有个工具(read4),每次给我们最多 4 个字符,但用户可能每次只要 1 个,或者想分多次拿走某个数量的字符。为了完成这个任务,我们得设计一个缓冲区,把每次多出来的字符存起来,等下一次调用再用上。

好,下面开始写代码:

class Solution {
    constructor() {
        this.buffer = []; // 缓冲区,用来存放多余的字符
    }

    read(buf, n) {
        let total = 0// 记录本次读取了多少字符

        while (total < n) {
            if (this.buffer.length === 0) {
                // 缓冲区空了,需要调用 read4
                let tempBuf = new Array(4); // 临时存放 read4 的结果
                let count = read4(tempBuf); // 调用 read4 获取字符

                if (count === 0) {
                    // 文件读取完了,直接退出
                    break;
                }

                // 把读取到的字符放到缓冲区
                this.buffer.push(...tempBuf.slice(0, count));
            }

            // 从缓冲区中取字符
            while (this.buffer.length > 0 && total < n) {
                buf[total++] = this.buffer.shift();
            }
        }

        return total; // 返回实际读取的字符数
    }
}

如果你看完代码还是懵的话,别急,我来拆解一下思路:

  1. 我们维护了一个缓冲区 this.buffer,用来存储每次调用 read4 多出来的字符。比如,调用 read4 读了 4 个字符,但用户只需要 2 个,那多出来的 2 个就丢到缓冲区里。

  2. 每次调用 read 时,先从缓冲区拿字符,如果缓冲区不够,就调用 read4 去读更多字符。

  3. 读完 read4 后,把结果存到缓冲区,并继续从中取字符,直到满足用户需求或者文件读完。

这么做有什么好处呢?就是无论用户调用 read 的方式多奇葩,我们都能通过缓冲区保存状态,确保不会漏读或者重复读字符。

举个例子,假设文件内容是 "abcdefg",用户分三次调用 read,每次分别需要 1、5、1 个字符。我们看一下代码是怎么工作的:

  • 第一次调用

    • 缓冲区为空,调用 read4,读到 "abcd"
    • 用户只需要 1 个字符,返回 "a",剩下 "bcd" 存进缓冲区。
  • 第二次调用

    • 缓冲区有 "bcd",调用 read4,读到 "efg"
    • 用户需要 5 个字符,从缓冲区拿 "bcd",再从新读取的字符中拿 "ef",返回 "bcdef",剩下 "g" 存进缓冲区。
  • 第三次调用

    • 缓冲区有 "g",用户只需要 1 个字符,直接从缓冲区拿 "g",返回。

整个过程就是这么循环往复,直到文件读完。

再强调几点细节:

  1. 缓冲区的作用是核心,没有它,我们没法处理用户分次调用 read 的情况。
  2. 每次调用 read4 都是大操作,所以尽量只在缓冲区不够用时调用,能减少不必要的开销。
  3. 最终返回的字符数不能超过 n,这个需求我们通过 total 变量控制。

写到这里,我觉得这道题的核心其实是“状态管理”——如何用缓冲区保存上次调用的状态,并在下次调用时继续利用。这个技巧在很多场景里都用得到,尤其是流处理或者分块读取数据的时候。

怎么样,是不是没想象中那么难?

目前,对编程、职场感兴趣的同学,大家可以联系我微信:golang404,拉你进入“程序员交流群”。

虎哥私藏精品 热门推荐

虎哥作为一名老码农,整理了全网最前端资料合集

资料包含了《前端面试题PDF合集》、《前端学习视频》、《前端项目及源码》,总量高达108GB。

全部免费领取全面满足各个阶段程序员的学习需求!

web前端专栏
回复 javascript,获取前端面试题。分享前端教程,AI编程,AI工具,Tailwind CSS,Tailwind组件,javascript教程,webstorm教程,html教程,css教程,nodejs教程,vue教程。
 最新文章