一些话
身处这个专业,身边的大佬们编程能力总是让人望尘莫及。早就觉得洛谷和力扣应该刷起来了,却总以“我又不着急找工作”“我也没法参加ACM比赛”为由。不知不觉大学已经过半,我们专业大四又全是实习(感觉大学又少了一年),真真是垂死病中惊坐起啊。不得不刷起来了。
大一时程设就因为种种原因与大佬们落下了差距,现如今不能再咸鱼下去了。先从剑指offer开始,尝试融会贯通编程语言、数据结构与算法。为什么不想直接工作还刷剑指offer呢,当然是为了之后实习面试准备呀(bushi,是因为它题最少哈哈哈)!我的设想是先拿C++通刷一遍(不追求时间空间开销,几乎都用蛮力法),之后或许会换python并逐渐优化一下开销。
大佬们都搭了自己的网站,我还是先把刷题的一些小心得写到csdn里,暑假有空的话再摸索着搭个站。
Offer 03 数组中重复的数字
找出数组中重复的数字。
在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1 的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。
来源:力扣(LeetCode)
哈哈,真的是很朴素的一道题了,既然找出任意一个数就行,就直接上最朴素蛮力法。Brute force yyds!大概就是设置了一个数组ifRepeated[]来记录,数组中第i个元素为true则表示数字i重复出现了。就是注意一下要先将所有值初始化为false,然后每遇到一个数字就改成true,修改前若检查为true即发现了第一个重复的数字,返回即可。
my 辣鸡 code
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
int length = nums.size();
bool *ifRepeated = new bool[length];
for(int i = 0; i < length; i++)
ifRepeated[i] = false;
for(int i = 0; i < length; i++) {
int j = nums[i];
if(ifRepeated[j] == true) return j;
else ifRepeated[j] = true;
}
return -1;
}
};
更好的方法
根据变治法我们可以知道,对输入做做处理就往往可以减少开销!所以当然要预排序啦,排序后相邻的两数相等就说明它是重复出现的数字了。刚学完变治法都没有第一时间想到它,实在惭愧惭愧。
Offer 04
在一个 n * m 的二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个高效的函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
来源:力扣(LeetCode)
不多解释了,直接上蛮力法。这岂不easy,一遍过。
执行错误的辣鸡code
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
int i = 0, j = 0;
int m = matrix.size(), n = matrix[0].size();
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
if(matrix[i][j] == target) return true;
if(matrix[i][j] > target) continue;
}
}
return false;
}
};
然后就报错
Line 1033: Char 9: runtime error: reference binding to null pointer of type ‘std::vector<int, std::allocator>’ (stl_vector.h)
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /usr/bin/…/lib/gcc/x86_64-linux-gnu/9/…/…/…/…/include/c++/9/bits/stl_vector.h:1043:9
最后执行的输入:
[]
0
and I was like, what这还能错?输入为空的时候为啥能有毛病呢,不就是m、n为零,不进入循环、最后返回false就好了吗?不得不说,因为始终没有培养出边界测试的习惯,这个问题真的是百思不得其解、我改了好多次也没想明白。过了好久才发现问题出在
int m = matrix.size(), n = matrix[0].size();
即使matrix为空,这个操作m当然能得到0的值,但仔细想想才发现matrix[0]都不存在,怎么能对一个不存在的对象调用size()呢!简直是太愚蠢了啊……然后才终于AC了
正确的蛮力法code
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
int i = 0, j = 0;
int m = matrix.size();
if(m == 0) return false;
int n = matrix[0].size();//matrix非空,matrix[0]才存在!
for(i = 0; i < m; i++) {
for(j = 0; j < n; j++) {
if(matrix[i][j] == target) return true;
if(matrix[i][j] > target) continue;
}
}
return false;
}
};
一点点小感想
对于Offer 03,评论区的一位老哥指出,
这道题在原书上绝对不是简单级别啊!
它考察的是程序员的沟通能力,先问面试官要时间/空间需求!!!
只是时间优先就用字典,
还有空间要求,就用指针+原地排序数组,
如果面试官要求空间O(1)并且不能修改原数组,还得写成二分法!!!
正确极了,沟通能力太重要了,甚至在敏捷开发中都占有一席。
对于Offer 04,只能说边界测试这种东西往往只有老师在文档中提出要求我才会想起去加。但对边界的保护应该是一个合格码农应铭记于心的东西,同理还有对于动态内存开辟后一定要记得收回(想起sj老师的银行ATM惨案哈哈哈)。
还有,对于题目中行列的递增特性可以抽象地理解为二叉搜索树,这样想到的话其实从右上角开始搜索就会快很多了。上学期学的ds仿佛都还给老师了,唉……
后记
想起大一室友荣誉课的作业里,对于输入卡得严极了。那时看到他们痛苦debug时只觉还好自己的作业简单,到今日被同学提醒要用大驼峰小驼峰命名、二元运算符两端要留空格时才悔不当初。编程这个东西,还得多吃堑才能长智啊!