您的位置:首页 > Web前端

剑指offer 01-06解答思路以及代码(顺序数组找特定数字,替换空格字符,链表反转输出,重建二叉树,两个栈实现队列效果,旋转数组最小元素)

2018-03-24 16:24 1046 查看
最近几天开始刷剑指,因为听说很多面试经典的题目都出自这里,所以大家都在看,那么说明该书还是有其独特的地方。刷题的地点就在牛客上,牛客确实是个挺不错的平台,不过得抱怨一下没有试运行,所以有些题目出现越界的情况也无从寻找源码,就无法调到编译器里面进行调试,确实时一件挺麻烦的事情,毕竟程序就是我写出来的,一眼看下去肯定感觉没啥问题啊。。。01 顺序数组找特定数字


题目不是很难,但是编程需要注意不要曲解题意,题目中只是说每一行都是顺序数组,但不代表下一行的第一个元素一定会小于上一行的每个元素。如此曲解题意,会造成最后输出的时候只寻找一行,而不会取搜索整个数组,可能会错过正确解。题目的解法是从下向上开始寻找比目标元素小的数,然后从左向右寻找等于目标元素的的解,如果小于则不断右移。代码如下:
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int row=array.size();
int col=array[0].size();
for(int i=row-1,j=0;i>=0&&j<col;){
if(array[i][j]<target){
j++;
continue;
}
if(array[i][j]>target){
i--;
continue;
}

if(array[i][j]==target)
return true;
}
return false;
}
};
02 替换空格字符

将空格转换成为别的元素,C++解题不同于python等可以自动申请空间,需要注意在替换的过程中需要申请新的空间,否则,当你改变元素的时候将会替换掉原字符串中的元素。所以首先需要统计字符串中空格的个数,然后申请新的大小的空间,在将其中的空格改变成为不同的元素。代码如下:
class Solution {
public:
 void replaceSpace(char *str,int length) {
        if(str==NULL&&length<=0)
            return;
        int orl=0;
        int i=0;
        int BlankNumb=0;
        while(str[i]!='\0'){
            ++orl;
            if(str[i]==' ')
                ++BlankNumb;
            i++;
        }
        int NewLength=orl+BlankNumb*2;
        if(NewLength>length)
            return;
        while(orl>=0&&NewLength>orl){
            if(str[orl]==' '){
                str[NewLength--]='0';
                str[NewLength--]='2';
                str[NewLength--]='%';
            }
            else
                str[NewLength--]=str[orl];
            orl--;
        }
 }
};

03 链表反转输出

该题目的第一个反应因为链表是单向的所以当指针向后指后就难统计前面元素,所以需要通过一个先进后出的序列来达成目的,于是大名鼎鼎的栈不就是干这事情的么。所以该题目通过栈来解决,将链表元素一一压入栈,然后将栈中元素一一push出来即可。代码如下:
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
stack<int> stack;
ListNode* pHead=head;
while(pHead!=NULL){
stack.push(pHead->val);
pHead=pHead->next;
}
vector<int> answer;
while(!stack.empty()){
answer.push_back(stack.top());
stack.pop();
}
return answer;
}
};

刚开始写该程序的时候将器判断条件写成了while(!pHead)结果出现了越界的情况。还是对于判断条件理解的不够深刻啊!仔细想想应该用while(pHead)就可以达到相同的效果。

04 重建二叉树

由于中序遍历的头一个元素必定为根节点,所以通过在前序序列中寻找根节点可以以此确定出树的左子树和右子树,然后通过遍历,不停确定其左右子树,即可输出重建的二叉树。代码如下
/**
* 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) {
if(pre.empty()||vin.empty())
return NULL;
TreeNode* head=new TreeNode(pre[0]);
vector<int> pre_left,pre_right,vin_left,vin_right;
int root=0;
for(int i=0;i<vin.size();i++){
if(pre[0]==vin[i]){
root=i;
break;
}
}
for(int i=0;i<root;i++){
pre_left.push_back(pre[i+1]);
vin_left.push_back(vin[i]);
}
for(int i=root+1;i<vin.size();i++){
pre_right.push_back(pre[i]);
vin_right.push_back(vin[i]);
}
head->left=reConstructBinaryTree(pre_left,vin_left);
head->right=reConstructBinaryTree(pre_right,vin_right);
return head;
}
};

05 两个栈实现队列效果

通过两个栈实现队列的效果,即将一个元素先入后出改为先进先出,所以当输入为12345时,栈输出为54321,而队列输出为12345。第一反应是将第一个栈的元素压入第二个栈就能达到效果,所以代码如下:
class Solution
{
public:
void push(int node) {
stack1.push(node);
}

int pop() {
while(!stack1.empty()){//当栈1不为空时,将其元素压入栈2
int top=stack1.top();
stack2.push(top);
stack1.pop();
}
int result=stack2.top();
stack2.pop();
return result;
}

private:
stack<int> stack1;
stack<int> stack2;
};

然而事实上并通过不了编译,因为当其不是将所有元素压入栈1的时候,即在其中插入pop操作的时候,其输出会有问题。应该对先前压入栈的元素和之后压入栈的元素有一个辨别,然后判断先将先压入栈二的元素全部输出以后再将栈1后面的元素压入栈2,将栈1作为一个类似寄存器的作用,再输出才能达到目的,更改后代码如下:
class Solution
{
public:
void push(int node) {
stack1.push(node);
}

int pop() {
if(stack2.empty()){
while(!stack1.empty()){
int top=stack1.top();
stack2.push(top);
stack1.pop();
}
}
int result=stack2.top();
stack2.pop();
return result;
}

private:
stack<int> stack1;
stack<int> stack2;
};

06旋转数组最小元素

反转元素寻找最小值,看似很难,所以第一反应sort()一下,输出第一个元素不久解决问题了:
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
sort(rotateArray.begin(),rotateArray.end());
return rotateArray[0];
}
4000

};
原来还怕会出什么问题,结果竟然就过了。。。。。。。。就是这么简单,没有任何毛病。不过感觉方法太讨巧了,所以又想了一个方法,既然递增数组是经过一次反转所形成的数组,所以只要输出第一个元素小于前面面元素不就是最小的元素的么,代码如下:
class Solution {
public:
int minNumberInRotateArray(vector<int> rotateArray) {
if(rotateArray.size()==0)
return 0;
int i=0;
for(;i<rotateArray.size();i++){
if(rotateArray[i+1]<rotateArray[i])
break;
}
return rotateArray[i+1];
}
};

本来以为还会有问题,结果又过了。。。。。。所以第二种方法的时间复杂度肯定比第一种要小,仅仅为n而已,具体时间的话优化了大概5ms吧,好像也不是特别多的样子。。。所以总体来说这道题确实不算难,不过这种解法对于多次反转的题目就无法有效的解决了,所以谁优谁劣各位自由判断。
当然刷了这些题目,虽然数量不多,但是个人还是有点感觉的,相对简单的题目有些时候会又思路出来。当然上面题目自然不全是我个人全部自己思考的答案,有一部分先看过书中的解答思路和代码后所写的代码,所以有什么不清楚的地方,各位可以在评论区提问或者找来原书看看。还是很不错的书的,感觉很多思路很新颖。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: