算法总结一

问题一:这是一个求数组中所有子数组中和最大的问题

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=0
for i=1,#priceBoDongArray do
	nowValue=priceBoDongArray[i];
     for j=i+1,#priceBoDongArray do
	 nowValue=priceBoDongArray[j]+nowValue
	 if nowValue>maxValue then
	     maxValue=nowValue
		 print("买入的天数为"..i.."卖出的天数为"..j)
	 end
	 end
end

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])
end

function 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=totalTemp
				start3=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=totalTemp
				end3=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=start3
			lastEnd=end3
			lastTotal=total3
		  end
		   print("最终start为"..lastStart.."最终end为"..lastEnd.."最终mid为"..mid.."最终total为"..lastTotal)
		  return lastStart,lastEnd,lastTotal
end


resultStart,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 s
	end
   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)
	end

	return s1..s2..s3
end

print(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 mytable5
end

mytable=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)
	   end
	end
end

for 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值