不知不觉就大三啦,前段时间开始系统地刷力扣为面试笔试做准备,看到有的易错地方和通过率比较低的题,觉得或许有同样在刷题的伙伴需要题解和代码,就决定捡起荒置的博客,对我刷过的题进行存档和整理,对我复盘应该也有一些帮助。
这里是c++选手,代码可能会有一些竞赛风格,而且对速度和使用内存没有太大的强迫症。这篇文章会按照“剑指offer”的顺序排列
刚开始写class简直是痛苦…不过收获也挺多的
剑指 Offer 03. 数组中重复的数字
题意:找出数组中任意一个重复的数字(数组中数据大小都在0~长度-1)
数据范围:长度
≤
\leq
≤ 1e5;
思路:
1.sort后直接比较相邻两元素是否相等,时间复杂度
O
(
n
log
2
n
)
O(n\log_{2}n)
O(nlog2n) ,几乎不需新开什么东西;
2.用数组记录一个数字是否出现过,时间复杂度
O
(
n
)
O(n)
O(n) ,需要额外开一个数组。
懒惰的我当然是方法2,时间是40ms超过83%,空间22.8M超过50%;
class Solution {
public:
int findRepeatNumber(vector<int>& nums) {
int n=nums.size();
int apr[100000+5]={0};
for(int i=0;i<n;i++)
if(apr[nums[i]])
return nums[i];
else apr[nums[i]]=1;
return 0;
}
};
剑指 Offer 04. 二维数组中的查找
题意:在一个每行每列都从上到下/从左到右递增的二维数组里寻找给定整数;
限制:0
≤
\leq
≤ n
≤
\leq
≤ 10000
≤
\leq
≤ m
≤
\leq
≤ 1000
思路:
1.使用lower_bound查找该数,时间复杂度
O
(
n
log
2
m
)
O(n\log_{2}m)
O(nlog2m) 战绩是惨烈的 32ms(38%) 12.8M(25%)
我一开始想着横着找一个区间,再在这两列找即可,后来发现这样是不能确保在有的情况下找到的。
2.记录行和列,从右上角(或左下角)开始寻找,在当前数字比目标数字大或小时都有可以去的地方,且放弃的那一行/列必定没有要找的数字,时间复杂度是
O
(
n
+
m
)
O(n+m)
O(n+m) 20ms 98% 12.7M 44%,如果改成从左下角找会(估计由于数据原因)慢不少
本懒人当然是用的1…不过2挺巧妙的,就也写了一次
注意:
1.lower_bound和upper_bound的区别(前者是第一个大于等于,后者是第一个大于)
2.数组size为0时若不处理可能re;
3.lower_bound可能返回最末尾未定义处,若不处理会re;
bb:这道题虽然很简单…但是谢谢它帮我复健了许久不用的lower_bound…尤其是用在STL上的;还有就是,听歌写代码真容易bug,各种少个=
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
int n=matrix.size(),m;
if(n)m=matrix[0].size();
if(n&&m)
{
for(int i=0;i<m;i++)
{
int pos=lower_bound(matrix[i].begin(),matrix[i].end(),target)-matrix[i].begin();
if(pos<n&&matrix[i][pos]==target)
return true;
}
}
return false;
}
};
优化版
class Solution {
public:
bool findNumberIn2DArray(vector<vector<int>>& matrix, int target) {
int n=matrix.size(),m,x,y;
if(n)m=matrix[0].size();
if(n&&m)
{
x=0;y=m-1;
while(x<n&&y>=0)
{
if(matrix[x][y]==target)return true;
else if(matrix[x][y]>target)y--;
else x++;
}
}
return false;
}
};
剑指 Offer 05. 替换空格
题意:把string里的空格替换为“%20”;
限制:0
≤
\leq
≤s 的长度
≤
\leq
≤ 10000
思路:直接扫描s一遍,另命一个string存储答案。若用string操作会比较慢
不过这道题好像大家都是0ms,我反而用了很大空间233
别的语言貌似写起来很快(虽然一共也没写几行233)
class Solution {
public:
string replaceSpace(string s) {
int len=s.length();
string ans;
for(int i=0;i<len;i++)
if(s[i]==' ')
ans+="%20";
else ans+=s[i];
return ans;
}
};
剑指 Offer 06. 从尾到头打印链表
题意:给定一个链表,用vector反过来存该链表每个节点的val;
思路:
1.遍历一次链表,正序存储下val,再头尾两两交换/新建一个vector反序存储一次
2.遍历一次链表获取链表长度,再遍历一次直接找出该存储的位置
两个思路都一样的丑,我就选了2 4ms(89%) 8.4M(89%)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
vector<int> reversePrint(ListNode* head) {
ListNode* pos=head;
int len=0,cnt=0;
while(pos!=NULL)
{
len++;
pos=pos->next;
}
vector<int>ans(len,0);
pos=head;
while(pos!=NULL)
{
cnt++;
ans[len-cnt]=pos->val;
pos=pos->next;
}
return ans;
}
};