牛客剑指offer 1~10题解

本文提供了一系列经典的编程问题及其解决方案,包括二维数组查找、字符串处理、链表操作、二叉树构造等,涵盖了数据结构和算法的基本知识点。

    每道题目能满足要求运行完所有测试例子,但并不追求最优解,只供参考,不解之处可以留言一起交流,共勉,加油!

1.二维数组中的查找

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

class Solution {
public:
    bool Find(int target, vector<vector<int> > array) {
        if(array.size() == 0 || array[0].size() == 0)
            return false;
        int Count = array[0].size();
        for(int i =0;i<array.size();i++)
        {
            if(array[i][Count-1] > target)
            {
                for(int j = 0;j<Count;j++)
                {
                    if(array[i][j] == target)
                        return true;
                    continue;
                }
            }
            else if(array[i][Count-1] == target)
                return true;
            continue;
        }
        return false;
    }
};

 

2.替换空格

题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

class Solution {
public:
    void replaceSpace(char *str,int length) 
    {
        if (str == nullptr)
			return;
        
		int size = strlen(str) + 1;
		int spaceSize = 0;

		for (int i = 0; i<size;i++)
		{
			if (str[i] == ' ')
				spaceSize++;
		}
		if (size+2*spaceSize> length)
			return;

		for (int i = size - 1; i>-1; i--)
		{
			if (str[i] == ' ')
			{
				int len = strlen(str + i) + 1;
				moveTwo(str + i, len);
				str[i] = '%';
				str[i + 1] = '2';
				str[i + 2] = '0';
			}
			else
				continue;
		}
	}
    //内存集体向右移两个字节 并置\0前两个字节
    void moveTwo(char* str,int length)
    {
        for(int i = length-1;i > -1;i--)
        {
            int before = i;
            int after = i+2;
            str[after] = str[before];
        }
        str[0] = str[1] = ' ';
    }
};

 

3.从尾到头打印链表

题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

/**
*  struct ListNode {
*        int val;
*        struct ListNode *next;
*        ListNode(int x) :
*              val(x), next(NULL) {
*        }
*  };
*/
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
        if(!head)
            return vector<int>();
        stack<int> Stack;
        while(head)
        {
            Stack.push(head->val);
            head = head->next;
        }
        vector<int> result;
        int size = Stack.size();
		for (int i = 0; i<size; i++)
		{
			result.push_back(Stack.top());
			Stack.pop();
		}
        return result;
    }
};

 

4.重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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) {
		int kB = 0;
		int kE = pre.size() - 1;
		int k2B = 0;
		int k2E = vin.size() - 1;
		//TreeNode* result = Tree(pre, vin, nullptr,kB, kE, k2B, k2E);
		TreeNode* result = Tree(pre,vin);
		return result;
	}
    TreeNode* Tree(vector<int> pre, vector<int> vin) {
		if (pre.empty() || vin.empty())
			return nullptr;

		TreeNode* root = new TreeNode(pre[0]);

		int pos =  Pos(vin, pre[0]); //pos 不为pre size
		//int leftLen = pos;
		//int rightLen = vin.size() - pos -1;

		vector<int> p1;
		vector<int> v1;
		for (int i = 0; i < pos;i++)
		{
			p1.push_back(pre[i+1]);
			v1.push_back(vin[i]);
		}
		root->left = Tree(p1,v1);
	
		vector<int> p2;
		vector<int> v2;
		for (int i = pos +1; i < vin.size();i++)
		{
			p2.push_back(pre[i]);
			v2.push_back(vin[i]);
		}
		root->right = Tree(p2,v2);
		return root;
	}
    int Pos(vector<int>& pre,int target)
	{
		int result = 0;
		for (auto i = 0; i < pre.size();i++)
		{
			if (target == pre[i])
				return result;
			result++;
		}
		return result;
	}
};

5.用两个栈实现队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

class Solution
{
public:
    void push(int node) {
        stack1.push(node);
    }

    int pop() {
        int front = -1;
        while(!stack1.empty())
        {
            int tmp = stack1.top();
            stack1.pop();
            stack2.push(tmp);
        }
       front = stack2.top();
        stack2.pop();
       while(!stack2.empty())
       {
           int tmp = stack2.top();
           stack2.pop();
           stack1.push(tmp);
       }
        return front;
    }

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) {
        if(rotateArray.empty())
            return 0;
        for(int i =0;i<rotateArray.size()-1;i++)
        {
            if(rotateArray[i] > rotateArray[i+1])
                return rotateArray[i+1];
        }
        return rotateArray[0];
    }
};

 

7.斐波那契数列

题目描述

大家都知道斐波那契数列,现在要求输入一个整数n,请你输出斐波那契数列的第n项(从0开始,第0项为0)。

n<=39

class Solution {
public:
    /*
    int Fibonacci(int n) {
        if(n <= 0)
            return 0;
        if(n == 1 || n == 2)
            return 1;
        return Fibonacci(n-1)+Fibonacci(n-2);
    }
    */
    int Fibonacci(int n) {
        if(n <= 0)
            return 0;
        if(n == 1 || n == 2)
            return 1;
        int result = 0;
        int ppre = 1;
        int pre = 1;
        for(int i = 3;i<=n;i++)
        {
            result = ppre+pre;
            ppre = pre;
            pre = result;
        }
        return result;
    }
};

 

8.跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。

class Solution {
public:
    int jumpFloor(int number) {
        if(number == 0 || number == 1)
            return 1;
        if(number == 2)
            return 2;
        int result = 0;
        int ppre = 1;
        int pre = 2;
        for(int i = 3;i<=number;++i)
        {
            result = ppre+pre;
            ppre = pre;
            pre = result;
        }
        return result;
    }
};

 

9.变态跳台阶

题目描述

一只青蛙一次可以跳上1级台阶,也可以跳上2级……它也可以跳上n级。求该青蛙跳上一个n级的台阶总共有多少种跳法。

class Solution {
public:
    int jumpFloorII(int number) {
        if(number == 0)
            return 1;
        if(number == 1)
            return 1;
        if(number == 2)
            return 2;
        int result = 0;
        for(int i = 0;i<number;i++)
        {
            result += jumpFloorII(number-i-1);
        }
        return result;
    }
};

 

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;
        return rectCover(number-2)+rectCover(number-1);
    }
};

 

### 光流法C++源代码解析与应用 #### 光流法原理 光流法是一种在计算机视觉领域中用于追踪视频序列中运动物体的方法。它基于亮度不变性假设,即场景中的点在时间上保持相同的灰度值,从而通过分析连续帧之间的像素变化来估计运动方向和速度。在数学上,光流场可以表示为像素位置和时间的一阶导数,即Ex、Ey(空间梯度)和Et(时间梯度),它们共同构成光流方程的基础。 #### C++实现细节 在给定的C++源代码片段中,`calculate`函数负责计算光流场。该函数接收一个图像缓冲区`buf`作为输入,并初始化了几个关键变量:`Ex`、`Ey`和`Et`分别代表沿x轴、y轴和时间轴的像素强度变化;`gray1`和`gray2`用于存储当前帧和前一帧的平均灰度值;`u`则表示计算出的光流矢量大小。 #### 图像处理流程 1. **初始化和预处理**:`memset`函数被用来清零`opticalflow`数组,它将保存计算出的光流数据。同时,`output`数组被填充为白色,这通常用于可视化结果。 2. **灰度计算**:对每一像素点进行处理,计算其灰度值。这里采用的是RGB通道平均值的计算方法,将每个像素的R、G、B值相加后除以3,得到一个近似灰度值。此步骤确保了计算过程的鲁棒性和效率。 3. **光流向量计算**:通过比较当前帧和前一帧的灰度值,计算出每个像素点的Ex、Ey和Et值。这里值得注意的是,光流向量的大小`u`是通过`Et`除以`sqrt(Ex^2 + Ey^2)`得到的,再乘以10进行量化处理,以减少计算复杂度。 4. **结果存储与阈值处理**:计算出的光流值被存储在`opticalflow`数组中。如果`u`的绝对值超过10,则认为该点存在显著运动,因此在`output`数组中将对应位置标记为黑色,形成运动区域的可视化效果。 5. **状态更新**:通过`memcpy`函数将当前帧复制到`prevframe`中,为下一次迭代做准备。 #### 扩展应用:Lukas-Kanade算法 除了上述基础的光流计算外,代码还提到了Lukas-Kanade算法的应用。这是一种更高级的光流计算方法,能够提供更精确的运动估计。在`ImgOpticalFlow`函数中,通过调用`cvCalcOpticalFlowLK`函数实现了这一算法,该函数接受前一帧和当前帧的灰度图,以及窗口大小等参数,返回像素级别的光流场信息。 在实际应用中,光流法常用于目标跟踪、运动检测、视频压缩等领域。通过深入理解和优化光流算法,可以进一步提升视频分析的准确性和实时性能。 光流法及其C++实现是计算机视觉领域的一个重要组成部分,通过对连续帧间像素变化的精细分析,能够有效捕捉和理解动态场景中的运动信息
微信小程序作为腾讯推出的一种轻型应用形式,因其便捷性与高效性,已广泛应用于日常生活中。以下为该平台的主要特性及配套资源说明: 特性方面: 操作便捷,即开即用:用户通过微信内搜索或扫描二维码即可直接使用,无需额外下载安装,减少了对手机存储空间的占用,也简化了使用流程。 多端兼容,统一开发:该平台支持在多种操作系统与设备上运行,开发者无需针对不同平台进行重复适配,可在一个统一的环境中完成开发工作。 功能丰富,接口完善:平台提供了多样化的API接口,便于开发者实现如支付功能、用户身份验证及消息通知等多样化需求。 社交整合,传播高效:小程序深度嵌入微信生态,能有效利用社交关系链,促进用户之间的互动与传播。 开发成本低,周期短:相比传统应用程序,小程序的开发投入更少,开发周期更短,有助于企业快速实现产品上线。 资源内容: “微信小程序-项目源码-原生开发框架-含效果截图示例”这一资料包,提供了完整的项目源码,并基于原生开发方式构建,确保了代码的稳定性与可维护性。内容涵盖项目结构、页面设计、功能模块等关键部分,配有详细说明与注释,便于使用者迅速理解并掌握开发方法。此外,还附有多个实际运行效果的截图,帮助用户直观了解功能实现情况,评估其在实际应用中的表现与价值。该资源适用于前端开发人员、技术爱好者及希望拓展业务的机构,具有较高的参考与使用价值。欢迎查阅,助力小程序开发实践。资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值