算法总结一
来源:互联网 发布:oracle sql case when 编辑:程序博客网 时间:2024/05/29 05:54
问题一:这是一个求数组中所有子数组中和最大的问题
1 暴力求解:c#代码
int[] priceArray = {100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97}; //第一步,先取得今天减去上一天的差的值 int[] priceBoDongArray = new int[priceArray.Length-1]; //这里注意的是i<priceArray.lenth不是<= 那样就越界了 for (int i=1;i<priceArray.Length;i++) { priceBoDongArray[i - 1] = priceArray[i] - priceArray[i - 1]; } //得到了价格的波动数组放到了priceBoDongArray数组中,这里注意的是,波动数组的第一个元素是 //第二天价格减去第一天的 //接着遍历价格数组从第一个元素开始遍历到最后一个元素,接着从第二个元素遍历到最后一个元素, //接着从第三个元素开始遍历到最后一个元素,这样取得所有该数组的所有子数组 //定义一个变量保存子数组的大小,定义一个变量保存目前得到的子串最大值 int y = 0;//y来保存当前取得的子串最大值 for (int i=0;i<priceBoDongArray.Length;i++) { int x = priceBoDongArray[i]; for (int j=i+1;j<priceBoDongArray.Length;j++) { x = x + priceBoDongArray[j]; if (x>y) { Console.WriteLine("买入的天数为:"+(i+1)+"卖出的天数为"+(j+1)); y = x; //这个太重要了,又忘了,如果得到了最大的数组,要把值赋给y } } } Console.ReadKey();
lua代码:
priceArray= {100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97}priceBoDongArray={}--取得波动数组for i=2,#priceArray do --lua中遍历是从1开始的,还有不是for i=2,#priceArray in pairs(priceArray) do table.insert(priceBoDongArray,priceArray[i]-priceArray[i-1]) --表的插入是table.insert(表名,数据) 不是表名.insert[]end--取得波动数组的所有子数组maxValue=0for i=1,#priceBoDongArray donowValue=priceBoDongArray[i]; for j=i+1,#priceBoDongArray do nowValue=priceBoDongArray[j]+nowValue if nowValue>maxValue then maxValue=nowValue print("买入的天数为"..i.."卖出的天数为"..j) end endend
2 二分法求解
它的思想是将该数组一分为二,数组为起始,中间和结束两段,那么出现三种可能
对于第三种方法直接处理,从mid向前加取得最大的子串即可加上mid+1向后加最大的子串,对于第一和二种可能,发现它又是和之前一样的问题,求一个数组中最大子串,那么就调用递归处理,由于调用递归,那么就写个函数,用一个数据接收结果
c#代码
struct structResult{ //注意struct 前面不加static public,而且里面的数据也要加上public才能调用 public int start; public int end; public int total; //子串的和 } static void Main(string[] args) { int[] priceArray = {100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97}; int[] pf = new int[priceArray.Length - 1];//价格波动的数组 for (int i = 1; i < priceArray.Length; i++) { pf[i - 1] = priceArray[i] - priceArray[i - 1]; } structResult str = GetResult(0,pf.Length-1,pf); Console.WriteLine("得到的最大子串起始位置为"+str.start+"结束位置"+str.end); Console.ReadKey(); } static structResult GetResult(int start, int end, int[] array) //这里注意的是static或者是 public static或者private static { //退出循环条件 if (start == end) //这里注意的是退出循环的条件放到最前面,放到递归的前面,要不然无限递归了 { structResult str5; str5.start = start; str5.end = end; str5.total = array[start]; return str5; } int mid = (start + end) / 2; //不能是int mid=array.length/2; //第一种可能 structResult str2 = GetResult(start, mid, array); //第二种可能 structResult str3 = GetResult(mid + 1, end, array); //第三种可能 int total1 = 0; int totalTemp1 = array[mid]; int startIndex = mid; for (int i = mid; i >= start; i--) //注意是int i=mid自己老写成i=mid,还有i--习惯了i++ { total1 += array[i];//求前半段哪个子串和最大,找到最大值保存起始坐标 if (total1>totalTemp1) { totalTemp1 = total1; startIndex = i; } } int total2 = 0; int totalTemp2 = array[mid+1]; int endIndex = mid + 1; for (int i = mid + 1; i <= end; i++) { total2 += array[i];// 求前后段哪个子串和最大,找到最大值保存起始坐标 if (total2 > totalTemp2) { totalTemp2 = total2; endIndex = i; } } structResult str1; str1.start = startIndex; str1.end = endIndex; str1.total = totalTemp1+totalTemp2; //判断三种可能性哪个子串的和最大 if (str1.total > str2.total && str1.total > str3.total) { } else if (str2.total > str1.total && str2.total > str3.total) { str1.start = str2.start; str1.end = str2.end; str1.total = str2.total; } else { str1.start = str3.start; str1.end = str3.end; str1.total = str3.total; } return str1; }
lua代码:里面有错误,实在找不出来了
priceArray= {100,113,110,85,105,102,86,63,81,101,94,106,101,79,94,90,97}priceBodongArray={}for i=2,#priceArray do table.insert(priceBodongArray,priceArray[i]-priceArray[i-1])endfunction GetResult(start0,end0,array) --注意这里传入的参数不能写end,这与lua本身的end关键字重复了报错 if start0==end0 then --要写递归,先写退出循环的条件,注意是==不是=又犯错了 return start0,end0,array[start0] end mid =math.floor((start0+end0)/2) --这里math.floor的作用是两个数相除后向前取整, print("开始为"..start0.."结束为"..end0.."mid为"..mid) --第一二种情况 start1,end1,total1=GetResult(start0,mid,array) start2,end2,total2=GetResult(mid+1,end0,array) --第三种情况左半边 totalLeft,totalTemp=array[mid],0 --把两个值赋给两个值要付两遍 start3=mid for i=mid,start0,-1 do totalTemp=totalTemp+array[i] if totalTemp>totalLeft then totalLeft=totalTempstart3=i end end --第三种情况右半边 totalRight,totalTemp=array[mid+1],0 end3=mid+1 for i=mid+1,end0 do totalTemp=totalTemp+array[i] if totalTemp>totalRight then totalRight=totalTempend3=i end end print("左边start为"..start3.."右边end为"..end3.."mid为"..mid.."totalLeft为"..totalLeft.."totalRight为"..totalRight) total3=totalLeft+totalRight --最终比较三种结果的值 if total1>total2 and total1>total3 then --这里注意的是elseif不是else if 还有,后面要跟then 最后的else不跟then lastStart=start1 lastEnd=end1 lastTotal=total1 elseif total2>total1 and total2>total3 then lastStart=start2 lastEnd=end2 lastTotal=total2 else lastStart=start3lastEnd=end3lastTotal=total3 end print("最终start为"..lastStart.."最终end为"..lastEnd.."最终mid为"..mid.."最终total为"..lastTotal) return lastStart,lastEnd,lastTotalendresultStart,resultEnd,total= GetResult(1,#priceBodongArray,priceBodongArray)print("最大子串的起始位置为"..resultStart.."最大子串的结束位置为"..resultEnd)
问题二:有个n阶台阶,一次只能走1阶或者2阶台阶,那么有多少种走法呢?
关于递归的一些总结:
1,在递归的过程中要把这次遍历的所有可能都要涉及,比如如果n为偶数时候,有两种要么走2,要么走11,那么这两种都要包括,而且这两个分支分别又对应一次递归。
2,在递归时候,包括了好几种可能,要用几个不同的变量保存,最后再把这几个变量相加或者取最大最小看题目要求。如果用一个变量来保存多种可能,那么会混乱。
c#递归方式求解代码
static void Main(string[] args) { String s= Console.ReadLine(); int s1 = int.Parse(s); string s2 = ""; String result = GetResult(s1,s2); Console.WriteLine("输出为"+result); Console.ReadKey(); } static String GetResult(int s1,String s2 ) { if (s1==0 ) //终止条件 { s2 += "下一种情况:"; return s2; } String s3=""; //这里用变量s3,s4,s5来保存三种不同可能 String s4=""; String s5=""; if ((s1%2)==0) //判断奇数偶数,注意这里是%模2,不是/ { s1 -= 2; //这里易错的地方是有两种情况调用2次递归,但是下面的递归不要再写s1-=2,那么就减了2次就不对了 s3 += "11"+s2; s3 = GetResult(s1, s3); s4 += "2"+s2; s4 = GetResult(s1, s4); } else { s1 -= 1; s2 += "1"; s5 = GetResult(s1, s2); } return s2=s3+s4+s5; }输出为:
可能会问那么1211,1112,122这三种情况呢?其实把这个输出在折叠倒过来一次全了
C#迭代方式求解:
public struct struct1{ public int m; //结构体里面的变量要想在外部调用需要加public public string[] n; } static void Main(string[] args) { //我们把输出的所有走法放到一个数组中定义这个数组的大小是10000,那么每个元素都是一个走法路线 string[] str = new string[100000]; struct1 x= GetResult(7, str); //创建一个struct是 struct1 x;不是struct x; //最后遍历所有的路线,输出每个字符串, for (int i=0;i<x.m;i++) { Console.WriteLine(str[i]); } Console.ReadKey(); } static public struct1 GetResult(int n, string[] str) { int m = 0; //一共m种走法 struct1 struct3; while (true) { if (n==0) { break; //这里的break跳出的是while循环 } if (n%2==1) { str[m] += "1"; n = n - 1; m = m + 1; } else { //这里这注意的是使用遍历的方式,所以遍历的时候有多个可能性,那么还要遍历所有的可能性 for (int i=0;i<m;i++) { string s1 = str[i]; str[i] += "11"; str[i + m] = s1 + "2"; } m *= 2; // 注意这里是乘法因为添加了11和添加2有两种可能,多了一倍的种类 n = n - 2; } } struct3.m = m; struct3.n = str; return struct3; } }
lua代码:
注意的是
第一 for i=1,3 do正确,如果for 1,3 do这样就不对了
第二 lua中没有string或int格式,所以不能行拼接字符串那样进行字符串相加,如果拼接用s=s .." 1"
function GetResult(n,s) if n==0 then s=s.."下一种走法" return send local s1="" --对于局部变量一定要用局部变量,否则不加就出错 local s2="" local s3=""if (n%2)==1 then n=n-1 s=s.."1" s1=GetResult(n,s)else n=n-2 s2=s.."11" --这里很关键,如果是s=s.."11"就出错,必须用变量保存,但是其他2个位置不用变量保存也可以,为啥啊,想不通 s2=GetResult(n,s2) --原因可能是加上11是第二种可能如果用s接收,那么改变了第三种可能 s=s.."2" s3=GetResult(n,s)endreturn s1..s2..s3endprint(GetResult(7,s))以7为例,输出如下:
再来看下刚才的算法的不足,由于先判断奇数还是偶数,如果是奇数的话,就先加1了,所以只能遍历到122的情况没法遍历到221情况,所以要想得到所有解要把得到的反转,两个数组合并,且111反转不变还要用一个数组来接收,剔除多余元素
那么要遍历到所有的解法应该怎么做呢:
下面是另一种思路求解,该方法可以得到所有解:
//由于要接收多少种方法和所有走法的数组,用一个struct接收 public struct struct1 { public int m; //结构体里面的变量要想在外部调用需要加public public string[] n; } static void Main(string[] args) { //创建一个数组用来保存所有走法,设这个数组的大小是10000 string[] str = new string[10000]; struct1 st1 = GetResult(9); //创建一个struct是 struct1 x;不是struct x;这里是传的9阶台阶做的测试 struct1 st; //去除st1.n中的重复元素,用st来保存 int y = 0; st.n = str; for (int i = 0; i < st1.m; i++) { if (!(st.n).Contains(st1.n[i])) { st.n[y] = st1.n[i]; y++; } } st.m = y; //最后遍历所有的路线,输出每个字符串, Console.WriteLine("一共有"+st.m+"种走法"); for (int i = 0; i < st.m; i++) { Console.WriteLine(st.n[i]); } Console.ReadKey(); } static public struct1 GetResult(int n) { struct1 st1; struct1 st2; struct1 st3; struct1 st4; string[] str1 = new string[10000]; string[] str2 = new string[10000]; string[] str4 = new string[10000]; if (n == 1) //当n=1时,用一个字符串数组保存"1",走法为1,返回结构体 { str1[0] = "1"; st3.m = 1; st3.n = str1; return st3; } if (n == 2) //当n=1时,用一个字符串数组保存"11"和"2",走法为2,返回结构体 { str2[0] = "11"; str2[1] = "2"; st3.m = 2; st3.n = str2; return st3; } //当一个n阶台阶传进来,要么走一步要么走二步,所以要递归两种情况 st1 = GetResult(n-1); //取到走了一步的所有走法后,要遍历数组中所有字符串,每个字符串后面加1 for (int i = 0; i < st1.m; i++) { st1.n[i] =st1.n[i]+"1"; } st2 = GetResult(n - 2); //取到走了两步的所有走法后,要遍历数组中所有字符串,同时扩充数组一倍的大小, //后半段保存前半段的值,前半段字符串加上"2",后半段字符串加"11" for (int i = 0; i < st2.m; i++) { string s2 = st2.n[i]; st2.n[i + st2.m] = s2 + "2"; st2.n[i] += "11"; } st2.m *= 2; //扩容一倍那么走法数量加了一倍 st4.m = st1.m +st2.m; //最后把走一步后的所有走法和走两步的左右走法加起来用st4保存 st4.n = str4; //如果不这样,直接给st4.n赋值,那么st4里面的数组没初始化没分配多少个空间那么st4.n[i] = st1.n[i];会报错 for (int i=0;i<st1.m;i++) { st4.n[i] = st1.n[i]; st4.n[i+st2.m] = st2.n[i]; } return st4; }
输出结果如下:以5阶台阶为例
同理,lua代码如下
function GetResult(n) if n==1 then mytable1={"1"} return mytable1 end if n==2 then mytable2={"11","2"} return mytable2 end local mytable3=GetResult(n-1) --这里需要注意的是mytable3需要定义为local否则编译结果不正确 for k in pairs(mytable3) do mytable3[k]=mytable3[k].."1" end local mytable4=GetResult(n-2) local i=#mytable4 --如果mytable3[k+#mytable4]=...放到for循环里面那么会更改#mytable4的值,所以提出来for j=1,i do -- for k in pairs(mytable4) do 这样写不对,因为每次循环后添加了元素k也会+1,那么就循环无穷无尽了 mytable4[j+i]=mytable4[j].."2" mytable4[j]=mytable4[j].."11" end --最后定义一个表来把取得的table3,table4元素整合起来 local mytable5={} for k in pairs(mytable3) do table.insert(mytable5,mytable3[k]) end for m in pairs(mytable4) do table.insert(mytable5,mytable4[m]) end return mytable5endmytable=GetResult(7)for k in pairs(mytable) do --把mytable的重复元素去除掉 for p=k+1,#mytable do --这里不太明白如果把这行改成for p=k+1 in pairs(mytable) do就会报错,为什么啊 if mytable[k]==mytable[p] then table.remove(mytable,p) endendendfor k,v in pairs(mytable) do print(v)end这里注意的是for p=k+1 in pairs(mytable) do 是语法错误,如果递增的p变量给它赋值了,那么后面必须跟 ,#mytable也即for p=k+1,#mytable do,要么就是p不赋值,后面跟 in pairs(mytable) do
- 排序算法总结一
- 算法总结一
- 算法总结一
- 面试算法题总结(一)
- 排序算法总结(一)
- 排序算法总结(一)
- 查找算法总结(一)
- 查找算法总结(一)
- 查找算法总结(一)
- 算法 简单总结(一)
- 排序算法总结(一)
- 排序算法总结(一)
- 专题一总结 贪心算法
- 常用排序算法总结(一)
- 排序算法总结(一)
- 排序算法个人总结(一)
- 专题一 贪心算法总结
- 排序算法总结(一)
- jsonp调用
- 【JAVA基础】list和字符串判空
- 搬砖来的linux命令 (自己收藏)
- 【VC】VS2008+WDK 配置方法解析
- intellij idea出现“Usage of API documented as @since 1.6+”的解决办法
- 算法总结一
- leetcode 46. Permutations 全排列问题+递归
- ⑦ 设计模式之门面模式【 Facade Pattern】
- 基于js的简单队列实现
- 棋盘放车(DP状态压缩)
- Java多线程--内存模型
- React框架精髓
- 【C++】vector的使用方法
- MySQL建表规约