剑指offer面试题1-10

#1二维数组中的查找
在一个二维数组中,每一行元素都按照从这里写代码片左到右递增的顺序排序,每一列元素都按照从上到下递增的顺序排序。实现一个查找功能的函数,函数的输入为二维数组和一个整数,判断数组中是否含有该整数。
剑指offer面试题1-10_第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的大矩形,总共有多少种方法?

思想:动态规划

剑指offer面试题1-10_第2张图片
放置方法等效于: 斐波那契数列
可以横着/纵向放置,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];
    }
};

你可能感兴趣的:(C++)