怎么样,学习完前3章之后有没有按捺不住?是不是已经不满足于做课后练习了呢?
恰好今天是周末,时间比较宽裕,我们来刷一道leetcode
Two Sum | LeetCode OJ
给定一个整型数组和另外一个整数,在数组找出两个整数,使得它们的和等于给定的整数。返回这两个整数的下标。
假设总能找到这样的两个数,且结果唯一
给定 nums = [ 2, 7, 11, 15 ], target = 9,
因为 nums[ 0 ] + nums[ 1 ] = 2 + 7 = 9,
return [ 0, 1 ].
弄懂了题目的意思之后我们就正式开始解题了。
这里建议大家先自己尝试一下。
可能最容易想到的一个方法就是通过两个循环来解决这个问题
外层循环从0开始遍历:[ 02, 07, 11 ]
内层循环从1开始遍历:[ 07, 11, 15 ]
如果对应位置上的整数相加等于给定的值,则返回下标
我们把页面往下拖动,在下拉框里面选择”c++”,就可以开始撸代码了。
建议大家先去写写看,多想几种解题方法出来。
想到之后在网站上就可以直接编码了,不需要借助IDE。
我是这么写的:
class Solution {
public:
vector twoSum(vector& nums, int target) {
vector vecResult;
for( int i = 0; i < nums.size() - 1; ++i )
{
for( int j = i + 1; j < nums.size(); ++j )
{
if( nums[i] + nums[j] == target )
{
vecResult.push_back( i );
vecResult.push_back( j );
return vecResult;
}
}
}
return vecResult;
}
};
点击 “Run Code”,哦也,一次通过!
点击 “Submit Solution”,OK, Accepted!
点击 “Detail” 看一看,天啊撸,什么鬼。耗时809ms!击败了5.6%的用户!
这他妈的跟360提示开机速度击败了全国1%的用户一样埋汰人啊!!!
仔细研究研究:
nums.size()调用了太多次,如果先调用一次把结果存起来呢?
OK,
点击 “Edit Code”,修改代码
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> vecResult;
auto iSize = nums.size();
for( int i = 0; i < iSize - 1; ++i )
{
for( int j = i + 1; j < iSize; ++j )
{
if( nums[i] + nums[j] == target )
{
vecResult.push_back( i );
vecResult.push_back( j );
return vecResult;
}
}
}
return vecResult;
}
};
提交之后再来看一下详情,我擦,486ms了!击败了33.49%的用户!!!
提升了20多个百分点啊,查看一下被接受的提交总数是273183,这乘下来一下子前进了五万多名。自信心激增,有木有!!!
再一看,iSize - 1也调用了好多次,同样的问题嘛。好,也把它给提前存下来试试看。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> vecResult;
auto iSize = nums.size();
auto iOutterSize = iSize - 1;
for( int i = 0; i < iOutterSize; ++i )
{
for( int j = i + 1; j < iSize; ++j )
{
if( nums[i] + nums[j] == target )
{
vecResult.push_back( i );
vecResult.push_back( j );
return vecResult;
}
}
}
return vecResult;
}
};
提交,shit,496ms!怎么还耗时增加了? 难道定义一个临时量这么影响性能结果?
到底是怎么回事,各路大神能告诉我吗?
想了半天没想能,先把问题记录下来。咱们继续。
书上说可以用列表初始化的方式来初始化数组,咱们把返回值的地方改一改,看看能不能有所提升
ok
class Solution {
public:
vector twoSum(vector& nums, int target) {
auto iSize = nums.size();
for( int i = 0; i < iSize - 1; ++i )
{
for( int j = i + 1; j < iSize; ++j )
{
if( nums[i] + nums[j] == target )
{
return { i, j };
}
}
}
vector vecResult;
return vecResult;
}
};
499ms?这个统计没问题吧?
不过书上也说了,建议创建空的vector,然后动态添加元素。看来动态添加的效率果然要高一些
我们把 return { i, j } 改成创建一个临时量再返回试试
vector temp = { i, j };
return temp;
652ms,果然创建一个临时量挺占用时间的
当然这些都是我们粗浅的解释,在没有接触到更多知识之前不妨把这些记下来,留着以后探索。
想想还有什么可以改的???
序列中的元素有三种访问方式
我们只用了下标,范围for不容易用到这来,不如我们先试试迭代器?
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> vecResult;
int i = 0;
for( auto itr = nums.begin(); itr != nums.end() - 1; ++itr)
{
int j = i + 1;
for( auto itrInner = itr + 1; itrInner != nums.end(); ++itrInner )
{
if( (*itr) + (*itrInner) == target )
{
vecResult.push_back( i );
vecResult.push_back( j );
return vecResult;
}
++j;
}
++i;
}
return vecResult;
}
};
在写代码的时候我们就应该知道迭代器在这种查找下标的场合不太适用。
我们不得不定义两个变量i和j来记录下标
事实也正是这样,当我们submit代码的时候被拒绝了,原因是在大的数据集面前消耗了过长的时间。
好吧,目前看来我们会的也就这么多了。
真的是这样吗?还有没有其他方法没想到?再仔细看看笔记?
大家有没有尝试过把入参修改一下呢?
vector twoSum(const vector &nums, const int &target)
有没有不需要两个循环就能解决的办法呢?
如果自己实在想不出来,可以去讨论区看看别人的解法
Two Sum