Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: 修正 0015.三数之和.md 中的严重表述错误 #2526

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

WanpengXu
Copy link

@WanpengXu WanpengXu commented Apr 12, 2024

在本题的原版哈希解法中,如果对样例进行测试,会发现输出的[a, b, c]并不是递增顺序,如图。

Snipaste_2024-04-12_21-25-49

这并不影响判题,但是这反映出了一个问题,原题解把bc写反了,导致这部分的注释也是错的。本题的unordered_set事实上存储的是b,而不是c。对于内层循环,上轮拿到的数,如果在else分支中被存储进unordered_set,本轮循环拿到的数实际上大于等于unordered_set中的所有数,所以本轮拿到的是cunordered_set中是b,这样才符合大小关系。
此外,本 pr 补充了对于三段去重代码的详细解释,完整代码如下。

class Solution {
public:
    // 在一个数组中找到3个数形成的三元组,它们的和为0,不能重复使用(三数下标互不相同),且三元组不能重复。
    // 理论解法:a+b+c(存储)==0(检索) <=> c(存储)==0-(a+b)(检索)
    // 实际解法:a+b+c(存储)==0(检索) <=> b(存储)==0-(a+c)(检索)
    vector<vector<int>> threeSum(vector<int>& nums) {
        // 本解法的内层循环一边存储一边检索,所以被存储的应该是b,而不是c
        vector<vector<int>> result;
        sort(nums.begin(), nums.end());
        
        for (int i = 0; i < nums.size(); i++) {
            // 如果a是正数,a<=b<=c,不可能形成和为0的三元组
            if (nums[i] > 0)
                break;
            
            // [a, a, ...] 如果本轮a和上轮a相同,那么找到的b,c也是相同的,所以去重a
            if (i > 0 && nums[i] == nums[i - 1])
                continue;
            
            // 这个set的作用是存储b
            unordered_set<int> set;
            
            for (int k = i + 1; k < nums.size(); k++) {
                // [(-2x), ..., (x), (x), x, x, x, ...]
                // eg. [0, 0, 0]
                // eg. [-4, 2, 2]
                // eg. [(-4), -1, 0, 0, 1, (2), (2), {2}, {2}, 3, 3]
                // 去重b=c时的b和c,即第三个x到最后一个x需要被跳过
                if (k > i + 2 && nums[k] == nums[k - 1] && nums[k - 1] == nums[k - 2])
                    continue;
                
                // a+b+c=0 <=> b=0-(a+c)
                int target = 0 - (nums[i] + nums[k]);
                if (set.find(target) != set.end()) {
                    result.push_back({nums[i], target, nums[k]});   // nums[k]成为c
                    // 内层循环中,a固定,如果find到了和上轮一样的b,那么c也就和上轮一样,所以去重b
                    set.erase(target);
                }
                else {
                    set.insert(nums[k]);                            // nums[k]成为b
                }
            }
        }

        return result;
    }
};

其他语言的哈希解法或许也需要相应修改。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant