《剑指Offer》做题总结(一)
来源:互联网 发布:淘宝卖家淘宝客推广 编辑:程序博客网 时间:2024/06/06 02:56
虽然现在离找工作还有一年的时间,但是为了提升自身编程水平,另一方面为了将来工作做准备。
黑色加粗部分基本就是题目给出的部分,红色部分是自己需要注意的知识点。
1.二维数组中的查找
题目描述:
在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
思路:
基本思想就是遍历,将最终的数找到,有意思的是vector.at(0)的应用
代码:
class Solution {
public:
bool Find(int target, vector<vector<int> > array) {
int row=array.size();
int col=array.at(0).size();
for(int i=0;i<row;i++)
{
for(int j=0;j<col;j++)
{
if(array[i][j]==target)
return true;
else
continue;
}
}
return false;
}
};
2.替换空格
题目描述:
请实现一个函数,将一个字符串中的空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思路:
基本思想就是字符串的替换,但是这个里面的坑挺多的,一个就是各种读取情况的判断,还有一个就是字符串末尾的结束符的注意,还有一个就是看题目的时候没看懂的就是length代表不能超过的长度。
代码:
class Solution {public:
void replaceSpace(char *str,int length) {
int blanks=0;
int oldlength=0;
for(int i=0;str[i]!='\0';i++)
{
if(str[i]==' ')
blanks++;
oldlength++;
}
//判断新生成的字符串是否超过规定的要求
int newlength=oldlength+2*blanks;
if(newlength>length)
return;
char *str1=str+oldlength;
char *str2=str+newlength;
while(str1<str2)
{
if(*str1==' ')
{
*str2--='0';
*str2--='2';
*str2--='%';
} else{
*str2--=*str1;
}
--str1;
}
}
};
3.从头到尾打印链表
题目描述:
输入一个链表,从尾到头打印链表每个节点的值。
思路:
这个问题开始我想简单了,想着直接就是一个输入然后遍历链表,就可以输出了,结果不是这样。这里面有一个要注意的就是开头的vector<int>,这个就表示 返回值是这样的,很多时候我都忽略了返回值的问题。
代码:
/**
* struct ListNode {
* int val;
* struct ListNode *next;
* ListNode(int x) :
* val(x), next(NULL) {
* }
* };
*/
class Solution {
public:
vector<int> printListFromTailToHead(ListNode* head) {
vector<int>result;
std::stack<ListNode*>nodes;
ListNode* pNode=head;
while(pNode)
{
nodes.push(pNode);
pNode=pNode->next;
}
while(!nodes.empty())
{
pNode=nodes.top();
result.push_back(pNode->val);
nodes.pop();
}
return result;
}
};
4.重建二叉树
题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回
思路:
这个问题开始没有思路的,由于对树的概念掌握也不是很好。首先明确一个概念就是三种遍历,前序根遍历(根左右)、中序根遍历(左根右)、后序根遍历(左右根)。其实这道题也是根据这个来的。题目中提供的是前序和中序。所以可以根据前序把根节点找到,然后根据中序把把左右节点给划分开来。
代码:
class solution{
public:
treeNode* reconstructBinaryTree(vector<int> pre,vector<int> vin){
int inlen=vin.size();
if(inlen==0)
return NULL;
vector<int>left_pre,right_pre,left_in,right_in;
//创建根节点,根节点肯定是前序遍历的第一个数
int gen=0;
for(int i=0;i<inlen;i++)
{
if(vin[i]==pre[0])
{
gen=i;
break;
}
}
//对中序遍历,根节点左边的节点位于二叉树的左边,根节点右边的节点位于二叉树的右边
//利用上述这点,对二叉树节点进行归并
for(int i=0;i<gen;i++)
{
left_in.push_back(vin[i]);
left_pre.push_back(pre[i+1]);
//前序遍历第一个为根节点
}
for(int i=gen+1;i<inlen;i++)
{
right_in.push_back(vin[i]);
right_pre.push_back(pre[i]);
}
//和shell排序的思想类似,取出前序和中序遍历根节点左边和右边的子树
//递归,再对其进行上述的步骤 ,即再区分子树的左右子树 直到叶子节点
head->left=reconstructBinaryTree(left_pre,left_in);
head->right=reconstructBinaryTree(right_pre,right_in);
return head;
}
}
5.用两个栈实现队列
题目描述:
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思路:
对于这道题,我第一反应是基本概念,对就是将栈和队列的概念理清。队列是先进先出,栈是先进后出。发一张基本原理的示意图。大家就一目了然了。
本质上就是入队压入stack1,出队的时候将stack1的元素push进stack2中,然后将stack2中的顶端元素pop出来。当然 这里面需要涉及判断的过程。就是要全面考虑具体是什么时候弹出(在stack2的时候弹出)什么时候压栈(在stack1的压栈)
代码:
class Solution
{
public:
void push(int node) {
if(!stack1.empty())
{
stack1.push(node);
}else
{
int a;
while(!stack2.empty())
{
a=stack2.top();
stack1.push(a);
stack2.pop();
}
stack1.push(node);
}
}
int pop() {
int a;
if(stack1.empty())
{
a=stack2.top();
stack2.pop();
return a;
}else{
int a;
while(!stack1.empty())
{
a=stack1.top();
stack2.push(a);
stack1.pop();
}
a=stack2.top();
stack2.pop();
return a;
}
}
private:
stack<int> stack1;
stack<int> stack2;
};
6.旋转数组的最小数字
题目描述:
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思路:
这一题其实没啥思路可以说的,但是这一题是可以炫技的,我用的还是比较笨的方法,直接比较过去的。可以直接用比较聪明的方法。比如下面这个。另外还有一个就是旋转数组有特殊性,就是最小的数在分界线。
代码:
class Solution {public:
int minNumberInRotateArray(vector<int> rotateArray) {
sort(rotateArray.begin(),rotateArray.end());
return rotateArray[0];
}
};
7.斐波那契数列
题目描述:
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项。
n<=39
思路:
这一题开始的时候我也陷入了常规的错误。错误是什么呢。我打算采用递归的方法求解这道题目。但是递归是非常消耗计算资源的,一般递归那么几次就很厉害了。所以最后还是采用的数组的动态分配。但是有一个地方有个坑(但是也是我自己学习不扎实,int* m=new int[n])大体呢就是这么些。
代码:
class Solution {public:
int Fibonacci(int n) {
if(n<=1)
return n;
else{
int* m=new int[n+1];
m[0]=0;
m[1]=1;
for(int i=2;i<=n;i++)
m[i]=m[i-1]+m[i-2];
return m[n];
}
}
};
8.跳台阶
题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
这一题开始的时候,我想的简单了。我以为有多少种1,2的组合,没想到还必须有1,2的排序。后来经过一番分析:如果第一次跳知识1阶那么剩下的就是n-1阶,如果第一次跳的2阶,那么剩下的就是n-2阶。由之前的假设可以得出f(n)=f(n-1)+f(n-2);因此最终得出的就是斐波那契数列
代码:
class Solution {
public:
int jumpFloor(int number) {
int result[2]={0,1};
if(number<2)
return result[number];
long long fib_one=1;
long long fib_two=0;
long long fibN;
for(unsigned int i=1;i<=number;++i)
{
fibN=fib_one+fib_two;
fib_two=fib_one;
fib_one=fibN;
}
return fibN;
}
};
9.变态跳台阶
题目描述:
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
思路:
这一题采用数学归纳法得出,比较简单
代码:
class Solution {public:
int jumpFloorII(int number) {
return pow(2,number-1);
}
};
10.矩形覆盖
题目描述:
我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
思路:
这一题开始,我假设最多可能的情况,发现本质上这道题也就是青蛙跳阶梯的题目。为什么这么说呢?首先摆矩形最基本的形状是全是竖着和横着的,再其次就是横着和竖着的交替摆放的。其实就相当于青蛙跳一阶和跳两阶的区别。而本质上青蛙跳台阶就是斐波那契数列,在复习一遍斐波那契数列。
代码:
class Solution {public:
int rectCover(int number) {
//变相的青蛙跳台阶,也就是实现斐波那契数列
if(number==0)
return 0;
if(number==1)
return 1;
if(number==2)
return 2;
int f1=1;
int f2=2;
int fn;
for(int i=3;i<=number;i++)
{
fn=f1+f2;
f1=f2;
f2=fn;
}
return fn;
}
};
11.二进制中的1的个数
题目描述:
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
思路:
这一题开始我只考虑了正数的情况,对于负数的情况没有考虑。导致出现了错误。最终的解题也是通过一种很巧妙的方法。一个数的二进制存在多少个1。如果一个整数不为0,那么这个整数至少有一位是1。如果我们把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的所有的0都会变成1(如果最右边的1后面还有0的话)。其余所有位将不会受到影响。
代码:
class Solution {public:
int NumberOf1(int n) {
//本质上是整除和取余的应用
int count=0;
while(n!=0)
{
count++;
n=n&(n-1);
}
return count;
}
};
12.数值的整数次方
题目描述:
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
思路:
思路很简单,但是容易思考不全。主要的三个情况,=0、>0、<0
代码:
class Solution {
public:
double Power(double base, int exponent) {
double final_number=1;
if(exponent==0)
{
return 1.0;
}
else if(exponent>0)
{
while(exponent)
{
final_number=final_number*base;
exponent--;
}
}
else if(exponent<0)
{
while(exponent)
{
final_number=final_number/base;
exponent++;
}
}
return final_number;
}
};
13.调整数组顺序使奇数在偶数前面
题目描述:
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路:
思路比较简单就是遍历,然后将奇数先push_back,然后遇到偶数再push_back
代码:
class Solution {public:
void reOrderArray(vector<int> &array) {
vector<int>result;
for(int i=0;i<array.size();i++)
{
if(array[i]%2==1)
result.push_back(array[i]);
}
for(int i=0;i<array.size();i++)
{
if(array[i]%2==0)
result.push_back(array[i]);
}
array=result;
}
};
14.链表中倒数第k个节点
题目描述:
输入一个链表,输出该链表中倒数第k个结点。
思路:
这一题思路比较重要,首先是设置两个指针分别指向链表的头,然后第一个指针向后走k-1个位置,然后第二个节点开始出发,当第一个节点到达末尾的时候,第二个节点就到达了k位置。需要注意空非空以及第k个位置的判断。
代码:
/*struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* FindKthToTail(ListNode* pListHead, unsigned int k) {
if(!pListHead||k==0)
return NULL;
ListNode* front=pListHead;
ListNode* back=pListHead;
while(front->next && k>1)
{
front=front->next;
--k;
}
if(front==NULL || k>1)
return NULL;
while(front->next)
{
front=front->next;
back=back->next;
}
return back;
}
};
15.反转链表
题目描述:
输入一个链表,反转链表后,输出链表的所有元素。
思路:
这一题呢,就是前面的给最后面的,当前的给前面的,最后面给当前的,如果遇到最后的为NULL,就返回当前的值。
代码:
/*struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) :
val(x), next(NULL) {
}
};*/
class Solution {
public:
ListNode* ReverseList(ListNode* pHead) {
if(pHead==NULL)
return pHead;
ListNode* pre=NULL;
ListNode* cur=pHead;
ListNode* nxt=NULL;
ListNode* res=NULL;
while(cur!=NULL)
{
nxt=cur->next;
cur->next=pre;
if(nxt==NULL)
{
break;
}
pre=cur;
cur=nxt;
}
return cur;
}
};
- 《剑指Offer》做题总结(一)
- 《剑指Offer》做题总结(二)
- 《剑指Offer》做题总结(三)
- 《剑指Offer》做题总结(四)
- 剑指offer题一
- 剑指offer编程总结(Java实现)(一)
- 剑指Offer--我用JAVA做(一)
- 剑指Offer:不用加减乘除做加法(一刷)
- JavaScript--《剑指offer》-题一
- 剑指offer刷题总结
- 牛客网做题总结:剑指offer中题目,java版一
- 剑指offer经典编程题(一)
- 剑指offer | 训练题47:不用加减乘除做加法
- 【剑指offer】题47:不用加减乘除做加法
- 剑指offer-第三题方法总结
- 剑指offer第四题方法总结
- 剑指offer-第12题方法总结
- 剑指offer-第九题方法总结
- Single-image shadow detection and removal using paired regions学习解读
- 再谈非重复随机序列号生成算法
- jquery写的表单验证
- 快速扫描算法提取鱼眼图像有效区域
- H5手游页游的资源版本管理(带Egret例子)
- 《剑指Offer》做题总结(一)
- (二)在centos7 下安装docker
- tensorflow 设置图片大小与翻转
- 2017814作业
- phantomjs 抓取、截图中文网站乱码的问题的解决
- 装饰者模式
- 如何实现报表设计中的高精度报表套打?
- html学习总结1:标签、样式及属性
- ASP.Net Core与数据库结合