​LeetCode刷题实战556:下一个更大元素 III

本文详细介绍了如何使用C++解决LeetCode上的下一个更大元素III问题,通过寻找全排列并检查是否超出32位整数范围来找到大于原数的最小整数。文章提供了一种解决方案,包括代码实现和示例解释。

算法的重要性,我就不多说了吧,想去大厂,就必须要经过基础知识和业务逻辑面试+算法面试。所以,为了提高大家的算法能力,这个公众号后续每天带大家做一道算法题,题目就从LeetCode上面选 !

今天和大家聊的问题叫做 下一个更大元素 III,我们先来看题面:

https://leetcode-cn.com/problems/next-greater-element-iii/

Given a positive integer n, find the smallest integer which has exactly the same digits existing in the integer n and is greater in value than n. If no such positive integer exists, return -1.

Note that the returned integer should fit in 32-bit integer, if there is a valid answer but it does not fit in 32-bit integer, return -1.

给你一个正整数 n ,请你找出符合条件的最小整数,其由重新排列 n 中存在的每位数字组成,并且其值大于 n 。如果不存在这样的正整数,则返回 -1 。

注意 ,返回的整数应当是一个 32 位整数 ,如果存在满足题意的答案,但不是 32 位整数 ,同样返回 -1 。

示例                         

示例 1:

输入:n = 12
输出:21

示例 2:

输入:n = 21
输出:-1

解题

https://blog.youkuaiyun.com/weixin_44171872/article/details/107312518

主要思路:

首先将整数转化为对应的字符串,对字符串进行操作,这就相当于将原题转化为下一个全排列问题,只不过,为了避免越界,将最后的字符串先转化为long int 类型,然后和INT_MAX比较,决定输出哪个结果 .

class Solution {
public:
    int nextGreaterElement(int n) {
        string str=to_string(n);//将数组转化为字符串
        //寻找一个更大的全排列
        int i=str.size()-2;
        while(i>=0&&str[i]>=str[i+1])
            --i;
        if(i==-1)
            return -1;
        int tmp=str.size()-1;
        while (str[i] >= str[tmp])
        --tmp;
        swap(str[i],str[tmp]);
        reverse(str.begin()+i+1,str.end());
        //先将字符串转化为long int ,避免越界
        long int res=atol(str.c_str());
        return res>INT_MAX?-1:res;//根据是否越界,输出结果
    }
};

好了,今天的文章就到这里,如果觉得有所收获,请顺手点个在看或者转发吧,你们的支持是我最大的动力 。

上期推文:

LeetCode1-540题汇总,希望对你有点帮助!

LeetCode刷题实战541:反转字符串 II

LeetCode刷题实战542:01 矩阵

LeetCode刷题实战543:二叉树的直径

LeetCode刷题实战544:输出比赛匹配对

LeetCode刷题实战545:二叉树的边界

LeetCode刷题实战546:移除盒子

LeetCode刷题实战547:省份数量

LeetCode刷题实战548:将数组分割成和相等的子数组

LeetCode刷题实战549:二叉树中最长的连续序列

LeetCode刷题实战550:游戏玩法分析 IV

LeetCode刷题实战551:学生出勤记录 I

LeetCode刷题实战552:学生出勤记录 II

LeetCode刷题实战553:最优除法

LeetCode刷题实战554:砖墙

LeetCode刷题实战555:分割连接字符串

981ff45b088e83607450f9336ff3b48d.png

/** * implement a container like std::map */ #ifndef SJTU_MAP_HPP #define SJTU_MAP_HPP #include <cstdio> // only for std::less<T> #include <functional> #include <cstddef> #include "utility.hpp" #include "exceptions.hpp" namespace sjtu { template< class Key, class T, class Compare = std::less <Key> > class AAtree{ public: typedef pair<const Key, T> value_type; struct Node { Node *lson, *rson, *parent; int level; value_type data; Node(const value_type &d, int lv = 1, Node *p = nullptr, Node *l = nullptr, Node *r = nullptr) : data(d), level(lv), parent(p), lson(l), rson(r) {} ~Node() { data.~value_type(); } }; Node *root; size_t tree_size; Compare comp; AAtree(): root(nullptr), tree_size(0) {} AAtree(const AAtree &other) { root = copyTree(other.root, nullptr); tree_size = other.tree_size; } AAtree &operator=(const AAtree &other) { if (this != &other) { clear(root); root = copyTree(other.root, nullptr); tree_size = other.tree_size; } return *this; } ~AAtree() { clear(root); tree_size = 0; } Node *skew(Node *node) { if (!node || !node->lson) return node; if (node->lson->level == node->level) { Node *L = node->lson; node->lson = L->rson; if (L->rson) L->rson->parent = node; L->rson = node; L->parent = node->parent; node->parent = L; return L; } return node; } Node *split(Node *node) { if (!node || !node->rson || !node->rson->rson) return node; if (node->level == node->rson->rson->level) { Node *R = node->rson; node->rson = R->lson; if (R->lson) R->lson->parent = node; R->lson = node; R->parent = node->parent; node->parent = R; ++R->level; return R; } return node; } Node *insert(Node *node, const value_type &value, Node *parent = nullptr) { if (!node) { ++tree_size; return new Node(value, 1, parent); } if (comp(value.first, node->data.first)) { node->lson = insert(node->lson, value, node); node->lson->parent = node; } else if (comp(node->data.first, value.first)) { node->rson = insert(node->rson, value, node); node->rson->parent = node; } else return node; node = skew(node); node = split(node); return node; } // 删除节点时正确处理父子关系 // void erase(Node*& node, const Key& key) { // if (!node) return; // if (comp(key, node->data.first)) { // erase(node->lson, key); // } else if (comp(node->data.first, key)) { // erase(node->rson, key); // } else { // if (node->lson && node->rson) { // // 处理有两个子节点的情况 // Node* successor = findMin(node->rson); // Node *newNode = new Node(successor->data, node->level, node->parent, node->lson, node->rson); // if (newNode->lson) newNode->lson->parent = newNode; // if (newNode->rson) newNode->rson->parent = newNode; // if (newNode->parent) { // if (newNode->parent->lson == node) { // newNode->parent->lson = newNode; // } else { // newNode->parent->rson = newNode; // } // } // erase(newNode->rson, successor->data.first); // 递归删除后继节点 // delete node; // node = newNode; // } else { // Node* temp = node; // node = (node->lson) ? node->lson : node->rson; // delete temp; // 释放内存后,node指针已被上层更新 // } // } // // 删除后重新平衡 // if (node) { // node = skew(node); // node = split(node); // } // } Node *erase(Node *node, const Key &key) { if (!node) return nullptr; if (comp(key, node->data.first)) { node->lson = erase(node->lson, key); if (node->lson) node->lson->parent = node; } else if (comp(node->data.first, key)) { node->rson = erase(node->rson, key); if (node->rson) node->rson->parent = node; } else { if (!node->lson && !node->rson) { if (node->parent) { if (node->parent->lson == node) { node->parent->lson = nullptr; } else { node->parent->rson = nullptr; } } delete node; node = nullptr; --tree_size; return nullptr; } else if (!node->lson) { Node *temp = node->rson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } else if (!node->rson) { Node *temp = node->lson; temp->parent = node->parent; delete node; node = nullptr; --tree_size; return temp; } Node *predecessor = node->lson; while (predecessor->rson) predecessor = predecessor->rson; Node *newNode = new Node(predecessor->data, node->level, node->parent, node->lson, node->rson); if (newNode->lson) newNode->lson->parent = newNode; if (newNode->rson) newNode->rson->parent = newNode; if (newNode->parent) { if (newNode->parent->lson == node) { newNode->parent->lson = newNode; } else { newNode->parent->rson = newNode; } } newNode->lson = erase(newNode->lson, predecessor->data.first); if (newNode->lson) newNode->lson->parent = newNode; delete node; node = newNode; } if (node->lson && node->rson) { size_t min_level = node->lson->level < node->rson->level ? node->lson->level : node->rson->level; if (node->level > min_level + 1) { node->level = min_level + 1; if (node->rson && node->rson->level > node->level) node->rson->level = node->level; } } node = skew(node); node->rson = skew(node->rson); if (node->rson) node->rson->rson = skew(node->rson->rson); node = split(node); node->rson = split(node->rson); return node; } Node *find(Node *node, const Key &key) const { while (node) { if (comp(key, node->data.first)) node = node->lson; else if (comp(node->data.first, key)) node = node->rson; else return node; } return nullptr; } Node *findMin(Node *node) const { if (!node) return nullptr; // printf("In findmin: %d\n", (node)); while (node->lson) node = node->lson; // printf("finish find min\n"); return node; } Node *findMax(Node *node) const { if (!node) return nullptr; while (node->rson) node = node->rson; return node; } Node *successor(Node *node) const { // printf("in successor\n"); if (!node) return nullptr; // printf("in successor2\n"); if (node->rson) return findMin(node->rson); // printf("in successor3\n"); Node *parent = node->parent; while (parent && node == parent->rson) { node = parent; parent = parent->parent; } // printf("finish successor\n"); return parent; } Node *predecessor(Node *node) const { if (!node) return nullptr; if (node->lson) return findMax(node->lson); Node *parent = node->parent; while (parent && node == parent->lson) { node = parent; parent = parent->parent; } return parent; } Node *copyTree(Node *node, Node *parent) { if (!node) return nullptr; Node *newNode = new Node(node->data, node->level, parent); newNode->lson = copyTree(node->lson, newNode); newNode->rson = copyTree(node->rson, newNode); return newNode; } void clear(Node *node) { if (!node) return; clear(node->lson); clear(node->rson); delete node; node = nullptr; } }; template< class Key, class T, class Compare = std::less <Key> > class map { public: /** * the internal type of data. * it should have a default constructor, a copy constructor. * You can use sjtu::map as value_type by typedef. */ typedef pair<const Key, T> value_type; AAtree<Key, T, Compare> aa_tree; /** * see BidirectionalIterator at CppReference for help. * * if there is anything wrong throw invalid_iterator. * like it = map.begin(); --it; * or it = map.end(); ++end(); */ typedef typename AAtree<Key, T, Compare>::Node Node; class const_iterator; class iterator { private: /** * TODO add data members * just add whatever you want. */ map* container; Node *node; public: iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } iterator(const iterator &other):container(other.container), node(other.node) { // TODO } /** * TODO iter++ */ iterator operator++(int) { if (!node) throw invalid_iterator(); iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ iterator operator--(int) { iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.node && container == rhs.container; } bool operator==(const const_iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.node || container != rhs.container; } bool operator!=(const const_iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; class const_iterator { // it should has similar member method as iterator. // and it should be able to construct from an iterator. private: // data members. map* container; Node *node; public: // const_iterator(const map *c = nullptr, Node *n = nullptr): container(const_cast<map*>(c)), node(n) { // // TODO // } const_iterator(map *c = nullptr, Node *n = nullptr): container(c), node(n) { // TODO } const_iterator(const const_iterator &other): container(other.container), node(other.node) { // TODO } const_iterator(const iterator &other) { // TODO container = other.getContainer(); node = other.getNode(); } /** * TODO iter++ */ const_iterator operator++(int) { if (!node) throw invalid_iterator(); const_iterator temp = *this; node = container->aa_tree.successor(node); return temp; } /** * TODO ++iter */ const_iterator &operator++() { if (!node) throw invalid_iterator(); node = container->aa_tree.successor(node); return *this; } /** * TODO iter-- */ const_iterator operator--(int) { const_iterator temp = *this; if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return temp; } /** * TODO --iter */ const_iterator &operator--() { if (node == nullptr) { node = container->aa_tree.findMax(container->aa_tree.root); if (!node) throw invalid_iterator(); } else { node = container->aa_tree.predecessor(node); if (!node) throw invalid_iterator(); } return *this; } /** * a operator to check whether two iterators are same (pointing to the same memory). */ const value_type &operator*() const { if (!node) throw invalid_iterator(); return node->data; } bool operator==(const iterator &rhs) const { return node == rhs.getNode() && container == rhs.getContainer(); } bool operator==(const const_iterator &rhs) const { return node == rhs.node && container == rhs.container; } /** * some other operator for iterator. */ bool operator!=(const iterator &rhs) const { return node != rhs.getNode() || container != rhs.getContainer(); } bool operator!=(const const_iterator &rhs) const { return node != rhs.node || container != rhs.container; } map *getContainer() const { return container; } Node *getNode() const { return node; } /** * for the support of it->first. * See <http://kelvinh.github.io/blog/2013/11/20/overloading-of-member-access-operator-dash-greater-than-symbol-in-cpp/> for help. */ const value_type *operator->() const noexcept { // if (!node) throw invalid_iterator(); return &(node->data); } }; /** * TODO two constructors */ map(): aa_tree() {} map(const map &other): aa_tree(other.aa_tree) {} /** * TODO assignment operator */ map &operator=(const map &other) { if (this != &other) { aa_tree = other.aa_tree; } return *this; } /** * TODO Destructors */ ~map() {} /** * TODO * access specified element with bounds checking * Returns a reference to the mapped value of the element with key equivalent to key. * If no such element exists, an exception of type `index_out_of_bound' */ T &at(const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } const T &at(const Key &key) const { auto node = aa_tree.find(aa_tree.root, key); if (!node) throw index_out_of_bound(); return node->data.second; } /** * TODO * access specified element * Returns a reference to the value that is mapped to a key equivalent to key, * performing an insertion if such key does not already exist. */ T &operator[](const Key &key) { auto node = aa_tree.find(aa_tree.root, key); if (node) return node->data.second; aa_tree.root = aa_tree.insert(aa_tree.root, value_type(key, T())); return aa_tree.find(aa_tree.root, key)->data.second; } /** * behave like at() throw index_out_of_bound if such key does not exist. */ const T &operator[](const Key &key) const { return at(key); } /** * return a iterator to the beginning */ iterator begin() { return iterator(this, aa_tree.findMin(aa_tree.root)); } const_iterator cbegin() const { return const_iterator(const_cast<map*>(this), aa_tree.findMin(aa_tree.root)); } /** * return a iterator to the end * in fact, it returns past-the-end. */ iterator end() { return iterator(this, nullptr); } const_iterator cend() const { return const_iterator(const_cast<map*>(this), nullptr); } /** * checks whether the container is empty * return true if empty, otherwise false. */ bool empty() const { return aa_tree.tree_size == 0; } /** * returns the number of elements. */ size_t size() const { return aa_tree.tree_size; } /** * clears the contents */ void clear() { aa_tree.clear(aa_tree.root); aa_tree.root = nullptr; aa_tree.tree_size = 0; } /** * insert an element. * return a pair, the first of the pair is * the iterator to the new element (or the element that prevented the insertion), * the second one is true if insert successfully, or false. */ pair<iterator, bool> insert(const value_type &value) { auto node = aa_tree.find(aa_tree.root, value.first); if (node) return {iterator(this, node), false}; aa_tree.root = aa_tree.insert(aa_tree.root, value); node = aa_tree.find(aa_tree.root, value.first); return {iterator(this, node), true}; } /** * erase the element at pos. * * throw if pos pointed to a bad element (pos == this->end() || pos points an element out of this) */ void erase(iterator pos) { if (pos == end() || pos.getContainer() != this) throw invalid_iterator(); aa_tree.root = aa_tree.erase(aa_tree.root, (*pos).first); } /** * Returns the number of elements with key * that compares equivalent to the specified argument, * which is either 1 or 0 * since this container does not allow duplicates. * The default method of check the equivalence is !(a < b || b > a) */ size_t count(const Key &key) const { return aa_tree.find(aa_tree.root, key) ? 1 : 0; } /** * Finds an element with key equivalent to key. * key value of the element to search for. * Iterator to an element with key equivalent to key. * If no such element is found, past-the-end (see end()) iterator is returned. */ iterator find(const Key &key) { return iterator(this, aa_tree.find(aa_tree.root, key)); } const_iterator find(const Key &key) const { return const_iterator(const_cast<map*>(this), aa_tree.find(aa_tree.root, key)); } }; } #endif 这段代码,Q.erase(it--)会失效,为什么?
最新发布
05-28
<think>好的,我需要分析为什么在自定义的C++ map实现中,Q.erase(it--)操作会导致失效。首先,我得回顾一下STL中map的erase和迭代器行为。根据之前的引用,STL的map使用红黑树,erase操作返回下一个有效迭代器。而用户的问在于自定义map中同样的操作失效,可能涉及迭代器管理、删除逻辑或递减操作的问。首先,考虑迭代器失效的情况。在STL中,当erase被调用时,被删除元素的迭代器会失效,但返回下一个有效的迭代器。如果自定义的map没有正确实现这一行为,比如没有在erase后更新迭代器或维护红黑树的结构,就可能导致问。例如,如果erase后没有正确调整父节点或子节点的指针,迭代器可能指向无效的位置。 接下来,分析Q.erase(it--)的具体过程。后置递减操作符it--会先返回当前迭代器的副本,然后将原迭代器前移。如果自定义的迭代器在递减时没有正确处理红黑树的节点,比如在begin()位置递减导致未定义行为,或者在节点删除后没有正确更新前后节点的链接,就会引发错误。例如,在删除节点后,相邻节点的指针可能未被正确设置,导致后续操作访问无效内存。另外,自定义map的erase函数可能没有返回正确的下一个迭代器。STL的erase返回被删除元素的下一个迭代器,而如果自定义实现没有这样做,那么在执行erase(it--)时,可能无法正确获取有效的迭代器,导致后续操作失效。例如,若erase返回的是删除后的下一个元素,但自定义实现返回了错误的迭代器或未更新,就会出问。还需要考虑红黑树的删除逻辑是否正确。红黑树的删除涉及颜色调整和旋转操作,如果这些操作实现有误,可能导致树结构破坏,进而使迭代器在遍历时失效。例如,删除节点后未正确平衡树,导致某些节点的父节点或子节点指针错误,迭代器在移动时访问到无效节点。 此外,迭代器的实现方式也可能影响。如果自定义迭代器只是简单的指针,没有封装足够的逻辑来处理树结构的变化,那么在元素被删除后,迭代器可能仍然指向已被释放的内存,导致未定义行为。例如,迭代器没有在元素删除时检测到其有效性,继续使用就会崩溃。 总结可能的原因:1)erase未正确返回下一个迭代器;2)后置递减操作符实现有误,导致在删除前迭代器位置错误;3)红黑树删除逻辑错误,破坏结构;4)迭代器未正确处理失效情况,继续使用无效指针。需要进一步验证这些可能性,比如检查自定义map的erase返回值,迭代器的递减实现,以及红黑树的删除算法是否正确。此外,边界情况如删除begin()或end()位置的元素是否处理得当,也是关键点。</think>### 自定义`map`实现中`Q.erase(it--)`失效的原因分析 #### 1. **迭代器失效的底层机制** 在自定义`map`中,迭代器失效的核心问源于**删除操作破坏了底层红黑树节点的链接关系**。当执行`Q.erase(it--)`时,后置递减操作符`it--`会先将迭代器指向前驱节点,但若删除操作未正确处理节点间的指针关系,会导致后续迭代器移动时访问非法内存[^1][^2]。 **示例场景**: ```cpp // 自定义map的erase函数未正确处理父节点指针 Node* erase(Node* pos) { // 仅删除节点,未更新相邻节点的parent指针 delete pos; return pos->next; // 假设pos->next已被释放 } ``` #### 2. **后置递减操作符`it--`的实现缺陷** 若自定义迭代器的`operator--(int)`(后置递减)未正确处理边界条件或节点关系,可能在删除操作后产生无效迭代器。例如: - **未校验递减后的有效性**:当迭代器指向`begin()`时,`it--`可能指向非法哨兵节点。 - **未同步红黑树结构变化**:删除操作可能修改了前驱/后继节点的链接关系,但迭代器仍保留旧指针。 **数学表达**: 设迭代器当前位置为$n_i$,其前驱节点为$n_{i-1}$。若删除$n_{i-1}$后未更新$n_i$的`left`/`right`指针,则: $$ \text{next}(n_i) = \text{invalid\_pointer} $$ #### 3. **`erase`函数未返回有效迭代器** STL的`map::erase`会返回被删除元素的下一个有效迭代器[^3],而自定义实现若未遵循此逻辑,将直接导致`Q.erase(it--)`后续操作失效。例如: ```cpp // 错误实现:未返回有效迭代器 void erase(iterator it) { delete it.node; // 直接删除节点,未调整树结构 // 无返回值,导致外部无法获取下一个有效位置 } ``` #### 4. **红黑树删除逻辑错误** 红黑树的删除需要严格遵循**颜色调整**和**旋转规则**。若自定义实现未正确处理以下情况,迭代器将失效: - **双黑节点修正**:未正确处理删除黑色节点导致的“双黑”问。 - **兄弟节点颜色判断**:旋转逻辑错误会导致树结构失衡,破坏迭代器的遍历顺序。 #### 5. **边界条件未处理** - **删除第一个元素**:若`it`指向`begin()`,执行`it--`会触发未定义行为。 - **删除最后一个元素**:未正确处理`end()`迭代器的回退逻辑。 --- ### 解决方案与验证方法 #### 1. **修复迭代器递减操作** 确保`operator--`在递减前校验有效性,并同步红黑树的最新结构: ```cpp iterator operator--(int) { iterator tmp = *this; if (current_node != nullptr) { current_node = find_predecessor(current_node); // 需实现前驱查找函数 } return tmp; // 返回旧位置的副本 } ``` #### 2. **完善`erase`函数的返回值** 在删除节点后,显式返回下一个有效迭代器: ```cpp iterator erase(iterator pos) { Node* next_node = find_successor(pos.node); // 查找后继节点 delete_node(pos.node); // 实现红黑树删除逻辑 return iterator(next_node); // 返回后继节点的迭代器 } ``` #### 3. **验证红黑树删除逻辑** 通过单元测试检查删除操作后的树结构是否符合红黑树性质: - **性质1**:根节点为黑色。 - **性质2**:红色节点的子节点必须为黑色。 - **性质3**:从任一节点到其叶子节点的路径包含相同数量的黑色节点。 --- ### 示例:自定义`map`的正确删除逻辑 ```cpp // 红黑树删除核心逻辑(简化版) void delete_node(Node* z) { Node* y = z; Color original_color = y->color; Node* x = nullptr; if (z->left == nullptr) { x = z->right; transplant(z, z->right); } else if (z->right == nullptr) { x = z->left; transplant(z, z->left); } else { y = find_minimum(z->right); // 找后继节点 original_color = y->color; x = y->right; if (y->parent == z) { x->parent = y; } else { transplant(y, y->right); y->right = z->right; y->right->parent = y; } transplant(z, y); y->left = z->left; y->left->parent = y; y->color = z->color; } if (original_color == BLACK) { fix_delete(x); // 修正双黑问 } } ``` --- ### 总结 `Q.erase(it--)`在自定义`map`中失效的根本原因包括: 1. **迭代器管理缺陷**:未正确处理删除后的节点链接关系[^2]。 2. **红黑树实现错误**:删除逻辑未遵循平衡规则[^4]。 3. **操作符重载问**:后置递减未返回有效的临时副本[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值