花了几天时间把剑指 Offer的中等题刷完了。
稍微总结一下:
大概就这么些考点
二叉树
剑指 Offer 07. 重建二叉树:前序遍历和中序遍历的复习。map的应用,还有递归。
剑指 Offer 26. 树的子结构:二叉树递归,一直比两棵树,到NULL为止。
剑指 Offer 32 - III. 从上到下打印二叉树 III:BFS
剑指 Offer 33. 二叉搜索树的后序遍历序列:DFS判断
bool verify(vector<int>& postorder,int i,int j){
if(i>=j)return true;
int p=i;
while(postorder[p]<postorder[j])p++;
int m=p;
while(postorder[p]>postorder[j])p++;
return p==j&&verify(postorder,i,m-1)&&verify(postorder,m,j-1);
}
剑指 Offer 34. 二叉树中和为某一值的路径:DFS遍历所有路径然后满足要求的收入res数组
剑指 Offer 36. 二叉搜索树与双向链表:中序遍历加单开数组存储
DFS
剑指 Offer 12. 矩阵中的路径:DFS(剪枝和函数内包矩阵)
剑指 Offer 13. 机器人的运动范围:DFS(全局矩阵剪枝)
剑指 Offer 38. 字符串的排列:DFS,回溯(主要回溯完)visited数组的运用(节省时间复杂度)
DP
剑指 Offer 14 剪绳子:小数可以考虑DP,大数只能用规律:1段为3最佳,其次为2,最后一段1时,化前面一段为2*2;
剑指 Offer 46. 把数字翻译成字符串:DP
int f(int num){
if(num<10)return 1;
if((num/10)%10==1||(num/10)%10==2&&num%10<=5){
return f(num/100)+f(num/10);
}
else return f(num/10);
}
剑指 Offer 47. 礼物的最大价值:经典DP
剑指 Offer 48. 最长不含重复字符的子字符串:暴力,滑动窗口,DP
剑指 Offer 49. 丑数:暴力过不了,淦。只能DP,不过是三个有序数组的合并罢了
class Solution {
public:
int nthUglyNumber(int n) {
int a=0,b=0,c=0;
vector<int>dp(n+1);
dp[0]=1;
for(int i=1;i<n+1;i++){
int x1=dp[a]*2,x2=dp[b]*3,x3=dp[c]*5;
dp[i]=min(min(x1,x2),x3);
if(dp[i]==dp[a]*2)a++;
if(dp[i]==dp[b]*3)b++;
if(dp[i]==dp[c]*5)c++;
}
return dp[n-1];
}
};
剑指 Offer 60. n个骰子的点数:正向DP和反向DP
从小到大的DP:
vector<double>dp(6,1.0/6.0);
for(int i=2;i<=n;i++){
vector<double>tmp(5*i+1,0);
for(int j=0;j<dp.size();j++){
for(int k=0;k<6;k++){
tmp[j+k]+=dp[j]/6.0;
}
}
dp=tmp;
}
剑指 Offer 63. 股票的最大利润:双变量秒杀,DP范畴
剑指 Offer 66. 构建乘积数组:
位运算
剑指 Offer 16. 数值的整数次方:快速幂:转化为二进制来取
while(b){
if(b&1==1){
result*=x;
}
x*=x;
b>>=1;
}
剑指 Offer 56 - I. 数组中数字出现的次数:寻找异或结果第一个1的那一位来分组,分组异或。
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int ret=0;
for(int n:nums)ret^=n;
int dic=1;
while((dic&ret)==0){
dic<<=1;
}
int a=0,b=0;
for(int n:nums){
if(dic&n)a^=n;
else b^=n;
}
return vector<int>{a,b};
}
};
剑指 Offer 56 - II. 数组中数字出现的次数 II:二进制统计所有位余3,剩下的必然是那个数字。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans=0;
int bit=0;
for(int j=31;j>=0;j--){
for(int i=0;i<nums.size();i++){
bit+=nums[i]>>j&1;
}
ans=ans*2+bit%3;
bit=0;
}
return ans;
}
};
栈,链表,队列
剑指 Offer 31. 栈的压入、弹出序列:设置一个栈来搞
stack<int> V;
for (pushOrd = 0, popOrd = 0; pushOrd < pushV.size(); ++pushOrd) // 按顺序遍历
{
V.push(pushV[pushOrd]); // 入栈
while (!V.empty() &&popV[popOrd] == V.top()) // 如果栈顶元素等于出栈元素
{
V.pop(); // 出栈
popOrd += 1; // 向后移
}
}
剑指 Offer 35. 复杂链表的复制:哈希表/节点拆分
unordered_map<Node*,Node*>map;
while(cur!=NULL){
map[cur]=new Node(cur->val);
cur=cur->next;
}
cur=head;
while(cur!=NULL){
map[cur]->next=map[cur->next];//cur->next;自己写的时候写错了
map[cur]->random=map[cur->random];//cur->random;
cur=cur->next;
}
return map[head];
剑指 Offer 59 - II. 队列的最大值:用了个双向队列
可以从后面出去。pop_back!deque!
void push_back(int value) {
while(!d.empty()&&d.back()<value)d.pop_back();
d.push_back(value);
res.push(value);
}
字符串、自动机相关
剑指 Offer 20. 表示数值的字符串:自动机以及普通判断方法,这个题有点麻,看了半天似懂非懂,前几天看的现在有点不知所措
剑指 Offer 45. 把数组排成最小的数:字符串是以字典序比大小的
string a=to_string(nums[i]);
string b=to_string(nums[j]);
string x=a+b,y=b+a;
if(x>y)swap(nums[i],nums[j]);
剑指 Offer 67. 把字符串转换成整数:添加flag来识别正负
判断是否溢出:
for(;i<str.size()&&str[i]>='0'&&str[i]<='9';i++){
if(res>INT_MAX/10||res==INT_MAX/10&&(str[i]-'0')>7){
return flag==1?INT_MAX:INT_MIN;
}
res=10*res+(str[i]-'0');
}
其他思维题
剑指 Offer 04. 二维数组中的查找:选择一个合适的位置,比如左下和右上,保证两个方向遍历的单调性。
剑指 Offer 44. 数字序列中某一位的数字:数字,数位。
char转数字是char-‘0’。
int digit=1;
int start=1;
long count=9;//细节long
while(n>count){
n-=count;
start*=10;
digit+=1;
count=9L*start*digit;//细节9L
}
剑指 Offer 64. 求1+2+…+n:短路运算,感觉意义不大
int sumNums(int n) {
n && (n += sumNums(n-1));
return n;
}