为什么 LeetCode(力扣)「执行代码」正确,提交代码出错?

为什么有时在 LeetCode (力扣)上,Run Code(执行代码) 正确,Submit(提交代码)时提示 Wrong Answer(解答错误)?

看这篇文章你就懂了,真不是 LeetCode 出 Bug 了。


大家好,我是 「负雪明烛」,一位坚持 7 年写了 1000 篇 LeetCode 算法题题解的程序员。欢迎关注。

面试必会的算法题系列在写作中——

  1. 面试必会的算法题——前缀和
  2. 面试必会的算法题——求加法

今天分享的是刷题小经验 —— 为什么一个测试用例,在「执行代码」的结果正确,「提交」运行出错?

往事

谈起这个话题,我忍不住想起往事。

第一次遇到这个问题是我在大二刚开始刷 LeetCode 的时候(还没中文版力扣),那时候我的主语言是 Java,在本地编译器 Eclipse 上写完代码粘贴到 LeetCode 的代码框里,点击「Run Code」后,看测试用例能通过,然后就「Submit」了。

满心期待着出现了一个绿色的 Accept!

几秒种后,我傻眼了,我看到的是红色的 Wrong Answer!

当时是新入门的小白,完全不能理解为什么会出错,还以为是 LeetCode 出现 Bug 了 😂

当时我的同学中在刷题的只有我一个,也没有微信群交流,只能自己想办法。捯饬了半天才在网上找到了答案——原来这和 LeetCode 的评测机制有关。

复现

下面我就在中文力扣上复现一下当时的场景。

就像下面这样,LeetCode 第 1 题:两数之和。

假如我的代码是下面这样,注意 visited 定义的位置:

unordered_map<int, int> visited;
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        for (int i = 0; i < nums.size(); ++i) {
            if (visited.count(target - nums[i])) {
                return {visited[target - nums[i]], i};
            }
            visited[nums[i]] = i;
        }
        return {};
    }
};

题目默认的测试用例是 :

[2,7,11,15]

9

点击「执行代码」—— OK,没问题,输出和预期结果一致。

image.png

那就点击「提交」呗 —— 出现了「解答错误」!

image.png

出错的测试用例是:

[3,3]

6

然鹅,我看自己的代码应该没问题呢。所以我把这个测试用例放到测试用例的执行框里,点击「执行代码」,结果是 [0, 1] !和预期结果是一样的!

这到底是怎么回事呢?是力扣有 Bug 吗?

原因

其实不是力扣有 Bug,是我们没有理解力扣的评测机制。

力扣的判题机在读取您的代码后,对每个测试用例,都会初始化一次类,但全局变量和类内静态变量需要您手动初始化。

你可以把力扣的评测过程想象成下面这样:

unordered_map<int, int> visited;
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 你的代码
    }
};

int main() {
    string line;
    while (getline(cin, line)) {
        // 读取输入的 nums
        vector<int> nums = stringToIntegerVector(line);
        // 读取输入的 target
        getline(cin, line);
        int target = stringToInteger(line);
        
        // 每次实例化一个 Solution(),并执行其 twoSum 方法
        vector<int> ret = Solution().twoSum(nums, target);
		
        // 输出结果
        string out = integerVectorToString(ret);
        cout << out << endl;
    }
    return 0;
}

看到了吗?

  • 对于每个测试用例,力扣会实例化一个 Solution(),并执行其 twoSum 方法
  • 如果把 visited 放在了类 Solution 的外边,作为「全局变量」,那么对于所有测试用例是共享的。因此上一个测试用例的运行结果会影响下一个测试用例,导致「解答错误」。
  • 把「解答错误」的测试用例放到「测试用例」框里,再运行的结果是对的,因为只运行了一个测试用例,不会互相干扰。

正确做法

为了避免「全局变量」或者「类内的静态变量」在不同测试用例之间的干扰,我们有两种办法:

  1. 推荐做法:不使用「全局变量」或者「类内的静态变量」;
  2. 在 类内/函数内 对「全局变量」或者「类内的静态变量」执行初始化。

比方说,我们把 visited 的位置调整到 类内/函数内 ,从而避免了「全局变量」。

class Solution {
private:
    // 类内
    unordered_map<int, int> visited;
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        // 函数内
        // unordered_map<int, int> visited;
        for (int i = 0; i < nums.size(); ++i) {
            if (visited.count(target - nums[i])) {
                return {visited[target - nums[i]], i};
            }
            visited[nums[i]] = i;
        }
        return {};
    }
};

或者在函数内初始化 visited,比如在 twoSum() 方法中执行 visited.clear()

unordered_map<int, int> visited;
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        visited.clear();
        for (int i = 0; i < nums.size(); ++i) {
            if (visited.count(target - nums[i])) {
                return {visited[target - nums[i]], i};
            }
            visited[nums[i]] = i;
        }
        return {};
    }
};

上面写法中,我最推荐把 visited 变量写到 twoSum 以内。

为什么呢?

这样符合「最小作用域原则」。

最小作用域原则是指:把每个变量定义成只对需要看到它的、最小范围的代码段可见。

这样能规避很多意想不到的错误。

总结

在刷题的时候,应尽量避免使用「全局变量」或者「类内的静态变量」,因为它们可能导致不同「测试用例」互相干扰,导致「解答错误」。

定义变量应遵循「最小作用域原则」,能规避很多意想不到的错误。

明白了 LeetCode(力扣)的评测机制之后,能让我们刷题不糊涂👨‍💻👩‍💻

参考:

  1. https://support.leetcode-cn.com/hc/kb/article/1194344/
  2. https://www.ituring.com.cn/article/216213
### 回答1: "力扣执行出错" 是指在使用力扣 (LeetCode) 进行编程时, 代码执行过程中出现了错误。这可能是因为代码本身存在语法错误或逻辑错误, 也可能是因为输入数据不符合题目要求, 或者其他原因导致的。如果你在使用力扣时遇到了执行出错的问题, 建议你仔细检查你的代码, 确保代码正确性, 并且确保输入数据符合题目的要求。 ### 回答2: 力扣执行出错是指在力扣平台上运行代码时遇到了错误。出错可能有多种原因,比如代码逻辑错误、算法错误、语法错误等等。当代码运行出错时,力扣会给出相应的错误提示信息,帮助开发者找出问题所在,并进行修复。 执行出错可能会导致代码无法正常运行或产生错误的输出结果。在力扣平台上,出错会以红色的错误提示信息显示,开发者可以根据提示信息了解出错的具体原因,并针对性地修改代码。 对于力扣的参赛者来说,执行出错可能会影响他们的得分和排名。在某些比赛中,如果程序执行出错,得分将会受到一定的扣分。因此,及时发现和解决执行出错问题是很重要的。 对于编程学习者来说,执行出错是一种很常见的情况。通过分析和解决执行出错问题,可以帮助学习者提高编程能力和调试技巧,逐渐掌握解决问题的能力。 总之,力扣执行出错表示代码在运行过程中出现了错误。解决执行出错问题需要开发者仔细分析错误信息,并针对性地进行代码修改和调试。通过不断积累经验和学习,可以逐渐减少和避免执行出错的问题。
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值