#1二维数组中的查找
在一个二维数组中,每一行元素都按照从这里写代码片
左到右递增的顺序排序,每一列元素都按照从上到下递增的顺序排序。实现一个查找功能的函数,函数的输入为二维数组和一个整数,判断数组中是否含有该整数。
//例如查找元素7
//二位数组的规律是从左往右依次递增,从下往上依次递增
//可以根据待查元素,与起点位置比较,起点位置暂设为右上角(也可以选左下角)
//如果待查元素比右上角值小,则j-1向左移动
//如果待查元素比右上角值大,则i-1 向下移动
//如果待查元素等于该点,则找到了。
class Solution
{
public:
bool Find (int target, vector>array)
{
int row=array.size();
int col=array[0].size();
int i=0;
int j=col-1;
while(i=0)
{
if(array[i][j]target)
i++;
else
return ture;
}
return false;
}
}
#2空格替换
请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
思想:从后往前遍历,去移动字符位置,时间复杂度O(N)
//合法性检验
//计算空格,算出新数组的空间
//将old从后往前拷贝到new中,
//如果old遇到空格,new向前填充%20,new然后再往前走一步,接着new向前走
//如果old没有遇到空格,直接进行拷贝
class Solution {
public:
void replaceSpace(char str[],int length) {
if(str==NULL||length<0)
return ;
int count=0; //计算空格
int i=0;
int oldsize=0; //旧数组的大小
while(str[i]!='\0')
{
oldsize++;
if(str[i]==' ')
count++;
i++;
}
int newsize=oldsize+2*count; //新数组的大小
if(newsize>length)
return ;
int newindex=newsize; //新数组的下标
int oldindex=oldsize; //旧数组的下标
while(newindex>oldindex&&oldindex>=0)
//旧数组不为0且新数组下标大于旧数组,即一直循环
{
if(str[oldindex]==' ')
//如果旧数组遍历到空格,新数组开始填充字符%,然后向前移动继续遍历
{
str[newindex--]='0';
str[newindex--]='2';
str[newindex--]='%';
}
else
{ //若不是空格则移动字符,然后新数组向前走一步准备下次拷贝
str[newindex]=str[oldindex];
newindex--;
}
//旧数组移动完一次字符后,走向前一个位置准备下一次拷贝
oldindex--;
}
}
};
#3从尾到头打印链表
输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。
思想:将链表中结点的值存储到栈(后进先出)中,当栈不为空时对栈顶元素依次出栈操作,出栈元素一次插入vector中
class Solution {
public:
vector printListFromTailToHead(ListNode* head) {
//把链表的结点值输入到栈中
//当栈中元素不为空时,将栈顶元素插入vector中/
vector outnode;
stack innode;
while(head!=NULL)
{
innode.push(head->val);
head=head->next;
}
while(!innode.empty())
{
outnode.push_back(innode.top());
innode.pop();
}
return outnode;
}
};
#4重建二叉树
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思想:
找到根节点在中序遍历的下标,然后合法性检验
左边为左子树,右边为右子树
将根结点左边的中序遍历值插入到左子树中序遍历中
将根结点右边的先序遍历值插入到左子树先序遍历中(起点从pre[0+1]开始)
同理根结点右边的中序遍历插入到右子树的中序遍历中(起点从rootindex+1开始)
左子树先序遍历完后,右边的先序遍历值擦汗如到右子树的先序遍历中
然后递归插入左右子树
class Solution {
public:
TreeNode* reConstructBinaryTree(vector pre,vector vin) {
int inlen=vin.size(); //计算树结点个数
if(inlen==0) //合法性检验
return NULL;
int rootindex=0;
vectorleft_vin,left_pre,right_pre,right_vin;
TreeNode* head=new TreeNode(pre[0]);
for(int i=0;ileft=reConstructBinaryTree(left_pre,left_vin);
head->right=reConstructBinaryTree(right_pre,right_vin);
return head;
}
};
#5用两个栈实现队列
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
思想:
class Solution{
public:
//两个栈实现一个队列
//入队列: st1入栈
//出队列: st2出栈(当栈不为空),若st2为空则将st1数据转移到st2中
//取队首: 与出队列思想一样。
stack st1,st2;
void push(int value)
{
st1.push(value);
}
int pop()
{
if(st2.empty())
{
while(!st1.empty())
{
int a=st1.top();
st2.push(a);
st1.pop();
}
}
int a=st2.top();
st2.pop();
return a;
}
};
#6旋转数组的最小数字
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。 输入一个非减排序的数组的一个旋转,输出旋转数组的最小元素。 例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。 NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
思想:
暴力查找:从前往后遍历,找出最小的存储起来,依次与最小值比较,小于则保存时间复杂度O(N);
二分查找:题目条件数组为有序数组,则旋转后的两部分都是有序的,可以根据二分查找依次取一半比较。时间复杂度O(logN)
//合法性检验
//定义一个左下标和右下标,若左下标值大于等于右下标值进行循环
//如果左下标值《=中间变量 说明最小值在第二个数组中,更新中间变量值
//如果右下标值》=中间变量,说明最小值在第二个数组中,更新中间变量值
//更新一次中间变量,区间缩减一半。
//一直到左右变量相邻,退出循环。
class Solution {
public:
int minNumberInRotateArray(vector ve) {
//二分查找
if(ve.size()==0)
return 0;
int left=0;
int right=ve.size()-1;
int mid=-1;
while(ve[left]>=ve[right])
{
if(right-left==1)
{
mid=right;
break;
}
int mid=left+(right-left)/2;
if(ve[left]>=ve[mid])
{
left=mid;
}
if(ve[right]>=ve[mid])
{
right=mid;
}
}
return ve[mid];
}
};
#7斐波那契额数列
大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。
n<=39
思想: 递归,中间重复计算较多耗费空间
循环(动态规划)将前面计算的结果保存在变量中,避免重复 计算
class Solution {
public:
int Fibonacci(int n) {
if(n<=1)
return n;
if(n==2)
return 1;
int pre=1;
int mid=1;
int result=0;
for(int i=3;i<=n;i++)
{
result=pre+mid;
pre=mid;
mid=result;
}
return result;
}
};
#8跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
每次只能跳1级或者跳2级
跳1级剩余n-1种跳法,跳2级剩余n-2种跳法
初始状态 f(1)=1 f(2)=2;
递推式:f(n)=f(n-1)+f(n-2)
思想:基于斐波那契的扩展
class Solution {
public:
int jumpFloor(int number) {
int f[number+1];
f[1]=1;
f[2]=2;
if(number<=1)
return number;
for(int i=3;i<=number;i++)
{
f[i]=f[i-1]+f[i-2];
}
return f[number];
}
};
#9变态跳台阶
一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。
每次可以跳 1,2,3…n级
//动态规划
//状态f(n): 从0到N阶台阶的跳法
//递推 f(1)=1 f(2)=f(2-1)+f(2-2)
// f(n)=f(n-1)+f(n-2)+…f(n-n);
// f(n-1)=f(n-2)+f(n-3)+…f(n-n+1);
// f(n)=2f(n-1);
//初始值 f(0)=-1; f(1)=1;
//返回f(n);
class Solution {
public:
int jumpFloorII(int number) {
if(number<=0)
return -1;
else if(number==1)
return 1;
else
return 2*jumpFloorII(number-1);
}
};
#10矩形覆盖
我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?
思想:动态规划
放置方法等效于: 斐波那契数列
可以横着/纵向放置,f[n]=f[n-1]+f[n-2];
初始状态: f[1]=1 f[2]=2;
class Solution {
public:
int rectCover(int number) {
int f[number+1];
f[1]=1;
f[2]=2;
if(number<=1)
return number;
for(int i=3;i<=number;i++)
{
f[i]=f[i-1]+f[i-2];
}
return f[number];
}
};