不抄袭的班级成员
Posted
技术标签:
【中文标题】不抄袭的班级成员【英文标题】:Class member without copying 【发布时间】:2019-12-13 03:36:33 【问题描述】:我正在尝试为https://www.leetcode.com 上的编码挑战编写解决方案。 leetcode 解决方案的入口点是一个名为Solution
的类的方法。他们控制方法的名称,每个问题都不同。
我正在研究一种有点复杂的方法来解决问题,为了管理复杂性,我编写了很多辅助函数。大多数辅助函数都需要一些相同的变量,例如 vector<int>
我必须搜索一些东西。
我想避免将这些变量传递给我编写的每个辅助函数。我试图通过使它们成为Solution
的成员变量来做到这一点。我通常使用int
s 之类的原始变量来做到这一点,这不会影响空间复杂度,但我只是尝试使用向量来做到这一点,其中副本确实会影响空间复杂度我尝试坚持使用恒定空间解决方案。
如何将向量存储为类的成员变量而不复制它,最好是不使用指针?我不想更改我的代码来处理指针。
这是一个寻找数组最小值和最大值的假装问题的最小示例。如果我给出问题的解决方案,他们会通过将测试用例传递给Solution().findMaximumAndMinimum(testCase);
来测试我的程序。
class Solution
vector<int> numbers;
pair<int, int> findMaximumAndMinimum(vector<int>& A)
numbers = A;
return findMinimum(), findMaximum();
int findMaximum()
auto maximum = numbers.front();
for (auto number : numbers)
if (maximum < number)
maximum = number;
return maximum;
int findMinimum()
auto minimum = numbers.front();
for (auto number : numbers)
if (minimum > number)
minimum = number;
return minimum;
;
我要更改的是 sn-p 的第 5 行:numbers = A
。这将导致A
被复制到numbers
。我不希望复制发生:我正在努力制作一个尽可能少占用时间和空间的解决方案,而复制我正在搜索的向量肯定会占用大量空间。
总结:我正在尝试制作一个看起来有点像上面的解决方案,但针对的是一个不同且更难的问题。上面的 sn-p 在显示我想要的内容时故意做的很简单。我想避免将A
明确传递给Solution
的其他方法。
背景:
我最初尝试将向量转换为引用成员vector<int>& numbers
,但构造函数遇到了问题。我相信在这种情况下我无法使用默认构造函数,因此它被报告为“已删除”,正如this answer 所说。
Leetcode 将使用默认构造函数调用我的类。我无法控制。
也许我可以在Solution
中放置一个类并改用这个类,在那里我可以控制类的对象是如何构造的,因此引用成员变量不会造成麻烦,但我不想诉诸于此。我不希望我的程序在开始时缩进两次。
PS:欢迎提出如何不通过引用一个类的许多方法来绕过A
的建议。请记住约束:我的解决方案的入口点是一个名为Solution
的类的方法,我无法控制该方法的名称。 不欢迎提出解决上述问题的不同方法的建议,因为以上是人为的 MWE。
【问题讨论】:
通过引用每个成员传递向量,或者更好的是,完全摆脱这些成员,只需在您的findMaximumAndMinimum
成员中使用单遍循环来查找 both 极值。
std::vector
就像你写的那样是一个成员变量,你已经通过引用传递它,使用vector<int>&
。我不明白你的问题。
@Frontear 该行将传递的参数复制给成员。没有自引用分配。然后numbers
用于计算每个成员函数中的极值。
@WhozCraig 正如我在帖子中所说,我实际上并没有试图解决这个最小和最大问题。这个关于极值的假装问题只是我对我正在寻找的最小示例的尝试。我还说我试图避免将数组传递给每个函数。我正在研究的问题有点复杂,我喜欢在编程时使用许多命名函数来描述我在做什么;必须一遍又一遍地传递一个明显的变量会使它变得混乱。
@Frontear 是的,向量是成员变量。那不是我的麻烦。它不是某种形式的对另一个向量的引用。据我了解,我的 sn-p 的第 5 行将导致 A
被复制到 numbers
。我不想将A
复制到数字,我希望numbers
引用A
。这是一个每一个小副本都很重要的情况,这是一场竞争。因为这是一场比赛,所以我有这样的限制,即我的程序的入口点是一个类的方法。
【参考方案1】:
这是我的问题的一种可能的答案,但我想避免。如果我可以控制Solution
的构造方式,那么作为引用的成员变量就不是问题了。所以我创建了__actualSolution
一个类,我可以完全控制它的构造方式,然后在 leetcode 知道的类中使用__actualSolution
。但是……这看起来很复杂,很难理解。我问这个问题的目的是尽可能让一个复杂的程序保持可读性。
class __actualSolution
private:
vector<int>& numbers;
__actualSolution(vector<int>& A) : numbers(A)
public:
static pair<int, int> findMaximumAndMinimum(vector<int>& A)
auto s = __actualSolution(A);
return s.findMinimum(), s.findMaximum();
int findMaximum()
auto maximum = numbers.front();
for (auto number : numbers)
if (maximum < number)
maximum = number;
return maximum;
int findMinimum()
auto minimum = numbers.front();
for (auto number : numbers)
if (minimum > number)
minimum = number;
return minimum;
;
class Solution
public:
pair<int, int> findMaximumAndMinimum(vector<int>& A)
return __actualSolution::findMaximumAndMinimum(A);
我希望从进一步的答案中避免类似上述的事情。帮助我坚持一个类,并避免将A
传递给Solution
的每个方法,请记住,我正在处理的实际问题比这两个人为的方法有更多的帮助函数。
【讨论】:
【参考方案2】:假设你主要关心的是
如何将向量存储为类的成员变量而不复制它,最好不使用指针?
那么std::move() 可能适合您的需要。但是,为此,您必须同意将您的函数参数视为右值,并因此将其资源“窃取”而不是复制。
如果是这种情况,您可以按照以下步骤进行。
class Solution
public:
typedef std::pair<int, int> solution;
private:
std::vector<int> numbers;
solution s = INT_MAX, -INT_MAX ;
int& min = s.first;
int& max = s.second;
public:
const solution& findMaximumAndMinimum(std::vector<int>& A)
numbers = std::move(A);
min = max = numbers[0];
for (const auto& value : numbers)
if (value < min) min = value;
else if (value > max) max = value;
return s;
;
虽然 Leetcode 提交不包含 main()
,但我在此处添加它是为了说明行为。
int main()
std::vector<int> testCase = 4,7,6,1,5,2 ;
std::cout << "testCase size before 'move()' = " << testCase.size() << std::endl;
Solution::solution s = Solution().findMaximumAndMinimum(testCase);
std::cout << "testCase size after 'move()' = " << testCase.size() << std::endl;
std::cout << "Solution = " << s.first << ", " << s.second << "";
return 0;
输出:
//testCase size before 'move()' = 6
//testCase size after 'move()' = 0
//Solution = 1, 7
自 C++11 起,STL 容器支持移动语义。 除其他外,这意味着每当您制作 STL容器之间的赋值操作AND通知编译器 rhs 参数(也是一个 STL 容器)可以被视为一个可移动的右值,那么 rhs 值将被移动而不是复制。在一个情况下 大小为 n 的向量,而不是提升 n 个副本,这种分配“窃取”了 rhs 关联的指针及其缓冲区 尺寸。 这非常快,特别是在处理大向量时,因为复杂度从 O(n) 下降到 O(1)。
您可以在自己的类中嵌入移动语义,但这超出了本问题的范围。如果您想深入了解,请参考this text 作为起点。
【讨论】:
一个leetcode提交不包括main
,也不能控制main
,只能控制class Solution
。 findMaximumAndMinimum
之类的测试函数将使用左值调用,因此不能将参数更改为右值引用。
哦,非常感谢您指出这一点。我不熟悉 leetcode 及其限制。我已经编辑了我的答案以反映您的评论。现在,参数是一个左值,所有的处理都在函数内完成。我的测试都成功了。请让我知道我的 Solution
课程现在是否符合 Leetcode。再次感谢。
@RonaldChiesse 谢谢。我对破坏原作不高兴,但我认为这通常不会成为问题。这应该有助于解决许多 LC 问题。以上是关于不抄袭的班级成员的主要内容,如果未能解决你的问题,请参考以下文章