最长滑道问题(非递归,C++)
2017-05-11 20:01
267 查看
这是爱奇艺的一道算法题。
题目描述请参考博客http://blog.csdn.net/sinat_30186009/article/details/52356053,在此表示感谢。
基本思路参考了以上文章,但是上面文章中的算法是java版,这是次要的,主要的问题是算法用的是原始递归思想,这样会造成计算量及其大,时间复杂度为O(n^2)。
本文旨在用C++语言解决上述问题,并且在递归的基础上进行改进,使得时间复杂度降为O(n)。其中n为高度矩阵的元素个数即row*col。
代码说明:
输入:
高度矩阵行数: row
高度矩阵列数: col
高度矩阵 : dots
输出:
最长滑道值:LargestSlideValue
滑道长度矩阵:dotsLength,该矩阵最大值到最小值的路径即为最长滑道路径
函数findLargestSlide()调用次数:Call_Of_findLargestSlide()
简单对比一下改进前后的效果:
测试样例:
改进前:
改进后:
可以看出,最长滑道长度为17,改进前,函数findLargestSlide()调用841次,改进后为54次,因此我们用递归算法时一定要考虑是否可以优化。
滑道长度矩阵dotsLength中的每个值代表从该点开始滑下,可获得的滑道最长值。长度为17的最长滑道标注如下图:
意即从高度为23的顶端(dotsLength中17对应的点)沿着图中蓝线一直滑到高度为1的底部(dotsLength中1对应的点)。当然还有其他长度的滑道,可以从图中方便地找出来。
最后,关于时间复杂度的具体数值,时间复杂度在改进前后分别为O(n^2)和O(n),但需要注意的是,即使同样维度的矩阵,数值不同的时候函数findLargestSlide()的调用次数可能不同,但时间复杂度量级是相同的。
时间复杂度简要分析:
改进前:粗略计算应为30*30,但是不可能每个点都会讲所有点递归计算一遍,因此最终的结果841要小于30*30=900。
改进后:时间复杂度应该为30呀?为啥这里比30大呢?因为在main()函数内,每个元素均要计算基于它的最长滑道,均要调用一次findLargestSlide()函数,总共30个点,因此调用30次。但是要注意的是,主函数计算基于每个值的最长滑道时,并不知道这个值之前有没有被计算过,它只有按照main()函数的流程再次调用findLargestSlide()函数,进入之后才知道是否被计算过,因此要加上前面计算其他点时递归计算过该点的次数(每个点最多一次,可能0次),因此所以就比30大了,但绝对不会超过30*2-1=59(这种情况发生在计算每个点的最长滑道时都发现之前被递归计算过,除了第一个点)。因此精确的时间复杂度为:最好时为n次,最坏时为2n-1次。
举例:
测试数据(一种最坏情况):
另一种最坏情况:
以第一种最坏情况为例(都是一样的),第一次计算30对应的最长滑道时,已经递归计算了其他点的最长滑道(总共计算了30次),然而main()函数并不知道这一点呀,因此继续计算29对应的最长滑道,进去发现,哎呀!已经计算过了那太好了(但是记得从main()函数调用findLargestSlide()也要计数,加1次),同样,28,27,26,...,3,2,1,直到计算完毕,总共调用findLargestSlide()函数的次数为30+29*1=59次。
测试数据(一种最好情况):
在上面的最好情况下,每次只计算一个点对应的最长滑道,不会出现递归计算,总共调用findLargestSlide()函数的次数为30次(均为main()函数调用)。
就到这里啦,有不足的地方敬请指正,欢迎交流。
题目描述请参考博客http://blog.csdn.net/sinat_30186009/article/details/52356053,在此表示感谢。
基本思路参考了以上文章,但是上面文章中的算法是java版,这是次要的,主要的问题是算法用的是原始递归思想,这样会造成计算量及其大,时间复杂度为O(n^2)。
本文旨在用C++语言解决上述问题,并且在递归的基础上进行改进,使得时间复杂度降为O(n)。其中n为高度矩阵的元素个数即row*col。
代码说明:
输入:
高度矩阵行数: row
高度矩阵列数: col
高度矩阵 : dots
输出:
最长滑道值:LargestSlideValue
滑道长度矩阵:dotsLength,该矩阵最大值到最小值的路径即为最长滑道路径
函数findLargestSlide()调用次数:Call_Of_findLargestSlide()
#include <iostream> #include <vector> #include <iomanip> using namespace std; //减少寻找过程(前面几种算法都会重复计算,本算法记录每个点的最大路径,下次寻找到该点时直接加即可!降低时间复杂度关键思想) int countfindLargestSlide=0;//用于计录函数findLargestSlide调用次数 //寻找最长滑道路径(前后两点不等高) int findLargestSlide(int x,int y,const vector<vector<int> >& dots,vector<vector<int> >& dotsLength) { countfindLargestSlide++; int left=y-1; int right=y+1; int up=x-1; int down=x+1; int left_value=0; int right_value=0; int up_value=0; int down_value=0; if(left>=0&&dots[x][left]<dots[x][y]){ if(0==dotsLength[x][left])//如果为0,表示该点没有被计算过,因此需要调用findLargestSlide来寻找基于该点的最长滑道 dotsLength[x][left]=left_value=findLargestSlide(x,left,dots,dotsLength); else //如果不为0,表示该点已经被计算过,不用重新计算,下同(降低时间复杂度关键代码) left_value=dotsLength[x][left]; } if(right<=(int)dots[0].size()-1&&dots[x][right]<dots[x][y]){ if(0==dotsLength[x][right]) dotsLength[x][right]=right_value=findLargestSlide(x,right,dots,dotsLength); else right_value=dotsLength[x][right]; } if(up>=0&&dots[up][y]<dots[x][y]){ if(0==dotsLength[up][y]) dotsLength[up][y]=up_value=findLargestSlide(up,y,dots,dotsLength); else up_value= dotsLength[up][y]; } if(down<=(int)dots.size()-1&&dots[down][y]<dots[x][y]){ if(0==dotsLength[down][y]) dotsLength[down][y]=down_value=findLargestSlide(down,y,dots,dotsLength); else down_value= dotsLength[down][y]; } int max1=left_value>=right_value?left_value:right_value; int max2=up_value>=down_value?up_value:down_value; int max=max1>=max2?max1:max2; dotsLength[x][y]=max+1;//加上寻找点自身的路径长度1 return dotsLength[x][y]; } int main() { //行和列 int row,col=0; cout<<"please input row and col: "; cin>>row>>col; cout << "row= "<<row<<" "<<"col= "<<col << endl; cout<<"please input dotsMatrix:"<<endl; //矩阵(每点代表一个高度) vector<vector<int> > dots(row,vector<int>(col,0)); //输入矩阵 for(vector<int>& valrow:dots) for(int & valcol:valrow) cin>>valcol; //矩阵,记录每个点对应的滑道长度 vector<vector<int> > dotsLength(row,vector<int>(col,0)); cout<<"--------------------"<<endl; //输出矩阵以验证矩阵确实输入正确 cout<<"dots:"<<endl; for(int i=0;i<row;i++) { for(int j=0;j<col;j++) cout<<setw(4)<<dots[i][j]; cout<<endl; } int max_value=0; for(int i=0;i<row;i++) { for(int j=0;j<col;j++) { int current_value=findLargestSlide(i,j,dots,dotsLength); if(current_value>max_value) { max_value=current_value; } } } cout<<"--------------------"<<endl; cout<<"LargestSlideValue= "<<max_value<<endl; cout<<"--------------------"<<endl; //输出dotsLength,从该矩阵中可以方便直观地看出滑动路线(可能有多条,从最大值到最小值) cout<<"dotsLength:"<<endl; for(int i=0;i<row;i++) { for(int j=0;j<col;j++) cout<<setw(4)<<dotsLength[i][j]; cout<<endl; } cout<<"--------------------"<<endl; //输出调用findLargestSlide函数的次数,本程序时间复杂度为线性复杂度:O(n) cout<<"Call_Of_findLargestSlide(): "<<countfindLargestSlide<<endl; return 0; }
简单对比一下改进前后的效果:
测试样例:
改进前:
改进后:
可以看出,最长滑道长度为17,改进前,函数findLargestSlide()调用841次,改进后为54次,因此我们用递归算法时一定要考虑是否可以优化。
滑道长度矩阵dotsLength中的每个值代表从该点开始滑下,可获得的滑道最长值。长度为17的最长滑道标注如下图:
意即从高度为23的顶端(dotsLength中17对应的点)沿着图中蓝线一直滑到高度为1的底部(dotsLength中1对应的点)。当然还有其他长度的滑道,可以从图中方便地找出来。
最后,关于时间复杂度的具体数值,时间复杂度在改进前后分别为O(n^2)和O(n),但需要注意的是,即使同样维度的矩阵,数值不同的时候函数findLargestSlide()的调用次数可能不同,但时间复杂度量级是相同的。
时间复杂度简要分析:
改进前:粗略计算应为30*30,但是不可能每个点都会讲所有点递归计算一遍,因此最终的结果841要小于30*30=900。
改进后:时间复杂度应该为30呀?为啥这里比30大呢?因为在main()函数内,每个元素均要计算基于它的最长滑道,均要调用一次findLargestSlide()函数,总共30个点,因此调用30次。但是要注意的是,主函数计算基于每个值的最长滑道时,并不知道这个值之前有没有被计算过,它只有按照main()函数的流程再次调用findLargestSlide()函数,进入之后才知道是否被计算过,因此要加上前面计算其他点时递归计算过该点的次数(每个点最多一次,可能0次),因此所以就比30大了,但绝对不会超过30*2-1=59(这种情况发生在计算每个点的最长滑道时都发现之前被递归计算过,除了第一个点)。因此精确的时间复杂度为:最好时为n次,最坏时为2n-1次。
举例:
测试数据(一种最坏情况):
另一种最坏情况:
以第一种最坏情况为例(都是一样的),第一次计算30对应的最长滑道时,已经递归计算了其他点的最长滑道(总共计算了30次),然而main()函数并不知道这一点呀,因此继续计算29对应的最长滑道,进去发现,哎呀!已经计算过了那太好了(但是记得从main()函数调用findLargestSlide()也要计数,加1次),同样,28,27,26,...,3,2,1,直到计算完毕,总共调用findLargestSlide()函数的次数为30+29*1=59次。
测试数据(一种最好情况):
在上面的最好情况下,每次只计算一个点对应的最长滑道,不会出现递归计算,总共调用findLargestSlide()函数的次数为30次(均为main()函数调用)。
就到这里啦,有不足的地方敬请指正,欢迎交流。
相关文章推荐
- 汉诺塔问题C++的递归实现 [
- C++递归问题之三---0-1背包问题:给定两个值value和num,在1到num之间取值使这些数和为value,输出所有组合
- c/c++ 斐波那契数列 利用模板元解决递归慢的问题
- 递归与动态规划---最长递增子序列问题
- 用递归实现国王分橘子问题 C++
- C/C++ 最长平台问题 算法
- 从递归问题继续看c++数据结构
- [C++]连续最长括号匹配问题解决策略二(学习)
- [C++]连续最长括号匹配问题
- C++ 生牛递归问题
- 迷宫问题用递归求全部解和用栈求一个解(C++)
- 八皇后问题 回溯递归 -C++
- [LeetCode系列] 二叉树最大深度求解问题(C++递归解法)
- c++ 数据结构 用递归方法解决迷宫问题
- C++ 关于最长下降子序列问题
- C++递归问题之二——n皇后问题:以四、八皇后为例,给定n个皇后要求将它们放在一个n维矩阵中,任意两个皇后不能出现在同一行、列、主副对角线上,输出具体的摆放方式
- 学习C/C++语言:递归求解hanoi汉诺塔问题
- 使用C++递归求解跳台阶问题
- C++ 输出全排列 简单递归 N皇后问题
- 3行核心代码解决汉诺塔问题(C++递归实现)