算法总结一

来源:互联网 发布: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

原创粉丝点击