剑指offer是比较经典的面试题目,我决定在牛客网上做一下,把没做好的题记录下来。
1.请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
class Solution {
public:
void replaceSpace(char *str,int length) {
if(length<=0||str==NULL) return;
char* temp=str;
int lenori=0;int num=0;
while(*temp!='\0'){
lenori++;
if(*temp==' ') num++;
temp++;
}
int lennew=num*2+lenori;
if(lennew>length) return;
int indexnew=lennew;
int indexold=lenori;
while(indexold>=0){
if(str[indexold]==' '){
str[indexnew--]='0';
str[indexnew--]='2';
str[indexnew--]='%';
}
else {
str[indexnew--]=str[indexold];
}
indexold--;
}
}
};
2.输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
return buildtree(pre,vin,0,pre.size()-1);
}
TreeNode* buildtree(vector<int>& pre,vector<int>& vin,int first,int end){
if(pre.empty()||first>end) return NULL;
int val=pre.front();
auto mid=pre.begin();
pre.erase(mid);
auto it=vin.begin()+first;
for(;it!=vin.begin()+end+1;it++){
if(*it==val) break;
}
TreeNode* root=new TreeNode(val);
root->left=buildtree(pre,vin,first,it-vin.begin()-1);
root->right=buildtree(pre,vin,it-vin.begin()+1,end);
return root;
}
};
3.输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
虽然这道题我ac了,但是还是值得分享一下,主要是竟然连负数也可以不断地去掉最后一个1,这个算法还是挺牛逼的。
class Solution {
public:
int NumberOf1(int n) {
//if(n>0){
int num=0;
while(n){
n=n&(n-1);
num++;
}
//}
return num;
}
};
4.我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
class Solution {
public:
int rectCover(int number) {
if(number<3) return number;
int first=1,second=2,val=0;//斐波那契数列
for(int i=3;i<=number;i++){
val=first+second;
first=second;
second=val;
}
return val;
}
};
4.输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.
发现这种题还是不怎么会做
class Solution {
public:
vector<int> printMatrix(vector<vector<int> > matrix) {
vector<int > res;
if(matrix.empty()||matrix[0].empty()) return res;
int m=matrix.size();
int n=matrix[0].size();
int c=m>n?(n+1)/2:(m+1)/2;
int p=m,q=n;
for(int i=0;i2,p-=2)
{
for(int col=i;colfor(int row=i+1;row1]);
if(p==1||q==1) break;
for(int col=i+q-2;col>=i;col--)
res.push_back(matrix[i+p-1][col]);
for(int row=i+p-2;row>i;row--)
res.push_back(matrix[row][i]);
}
return res;
}
};
5.定义栈的数据结构,请在该类型中实现一个能够得到栈最小元素的min函数。
第二个栈存当前最小值,再次压进去
#include
class Solution {
public:
void push(int value) {
minvalue=std::min(value,minvalue);
stack1.push(value);
stack2.push(minvalue);
}
void pop() {
stack1.pop();
stack2.pop();
}
int top() {
return stack1.top();
}
int min() {
return stack2.top();
}
private:
stack<int> stack1;
stack<int> stack2;
int minvalue=INT_MAX;
};
6.输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)
这道题的陷阱是 一定要把原来的链表恢复原状,不能损坏原来的链表。
/*
struct RandomListNode {
int label;
struct RandomListNode *next, *random;
RandomListNode(int x) :
label(x), next(NULL), random(NULL) {
}
};
*/
class Solution {
public:
RandomListNode* Clone(RandomListNode* pHead)
{
if(!pHead) return pHead;
RandomListNode* step=pHead;
while(step){
RandomListNode* node=new RandomListNode(step->label);
RandomListNode* nextnode=step->next;
step->next=node;
node->next=nextnode;
step=nextnode;
}
step=pHead;
while(step){
if(step->random)step->next->random=step->random->next;
else step->next->random=NULL;
step=step->next->next;
}
step=pHead;
RandomListNode* newhead=new RandomListNode(0);
RandomListNode* now=newhead;
while(step){
now->next=step->next;
if(now->next)step->next=now->next->next;//千万注意,一定要把原来的链表恢复原状,不能损坏原来的链表。
now=now->next;
step=step->next;
}
return newhead->next;
}
};
7.输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
这道题就是要调,维护一个vector 存最小的k个数,然后按照顺序更新就行。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
if(k>input.size()) return {};
vector<int> res(k,0);
int i=0;
for(;ifor(;iint j=0;
for(;jif(input[i]<=res[j])
break;
}
if(jint m=0;
for(m=k-1;m>j;m--){
res[m]=res[m-1];
}
res[j]=input[i];
}
}
return res;
}
};
8.请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。
这道题不难,核心是递归函数的输入时两个,是左右。左的左,右的右。右的左,左的右。
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
*/
class Solution {
public:
bool isSymmetrical(TreeNode* pRoot)
{
if(!pRoot) return true;
return solve(pRoot->left,pRoot->right);
}
bool solve(TreeNode* left,TreeNode* right){
if((!left)&&(!right)) return true;
if((left==NULL)||(right==NULL)) return false;
if(left->val!=right->val) return false;
return solve(left->left,right->right)&&solve(left->right,right->left);
}
};
9.在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5
这道题最重要的是处理边界条件,比较消耗时间。经验就是凡是要考虑->next的属性,如->next->next或者->next->val的,都要考虑->next存不存在。
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};
*/
class Solution {
public:
ListNode* deleteDuplication(ListNode* pHead)
{
ListNode* newhead=new ListNode(0);
ListNode* first=pHead;
ListNode* now=newhead;
while(first){
while(first&&first->next&&first->next->val==first->val){
int mid=first->val;
while(first&&mid==first->val)
first=first->next;
}
now->next=first;
if(first)first=first->next;
now=now->next;
}
return newhead->next;
}
};