问题一:这是一个求数组中所有子数组中和最大的问题
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