classSolution { public: intfirstMissingPositive(vector<int>& nums){ int index, length; length = nums.size(); for (index = 0; index < length; ++index) { while (nums[index] > 0 && nums[index] <= length && nums[index] != nums[nums[index] - 1]) { swap(nums[index], nums[nums[index] - 1]); } } for (index = 0; index < length; ++index) { if (nums[index] != index + 1) { return index + 1; } } return length + 1; } };
AC 截图
题解分析
虽然这个题解顺利通过了测试,但是竟然还有 16.03% 的更优解?是我算法的问题吗?
打开最优解的示例代码一看:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
classSolution { public: // time: O(n), space: O(1) intfirstMissingPositive(vector<int>& nums){ int n = nums.size(); for (int i = 0; i < n; i ++) { while (nums[i] > 0 && nums[i] <= n && nums[nums[i]-1] != nums[i]) { swap(nums[i], nums[nums[i] - 1]); } } for (int i = 0; i < n; i ++) { if (nums[i] != i + 1) return i + 1; } return n+1; } };
乍一眼看过去……这不和我是一样的吗?而且 i++ 的效率显然不如 ++i,怎么可能还比我快?他甚至还在每个 for 循环中重新声明变量 i,这肯定是比我直接声明好进行复用要更慢啊!不信邪的我也改了一下自己的代码,于是有了题解2……
令人吃惊的是:两者的汇编代码几乎是完全一样的!唯一的区别在于:由于 index 和 length 的声明先后顺序不同,其在内存中的地址(相对于ebp)在两个函数中对调了。这虽然没能验证反复声明反而更快的结果,但至少说明了 在 for 循环初始化语句中声明变量,不会比在外部声明更耗时。同时也告诉我们,单纯通过高级语言编写中的直觉推测程序在机器上执行的效率是危险的。
那么,为什么 solve2 会更快呢?事实上,经过测试,在 Windows VS 环境下,二者速度是基本一致的。那么是编译器和环境的问题吗?