1.n个骰子的点数
思路:基于循环的解法,加入一个新的骰子,此时,和为n的骰子出现的次数应该等于上一轮循环中骰子点数和为n-1、n-1、n-3、n-4、n-5、n-6的和。
void PrintProbability(int number) //number是骰子数
{
if(number<1)
return;
int* pProbabilities[2]; //定义两个数组 注意这是两个指针
pProbabilities[0]=new int[6*number+1]; ///包含和的所有可能。
pProbabilities[1]=new int[6*number+1];///用两个数组的作用是,每增加一个骰子,交替使用两个数组
for(int i=0;i<6*number+1;i++) ///初始化两个数组
{
pProbabilities[0][i]=0;
pProbabilities[1][i]=0;
}
int flag=0;
for(int i=1;i<=6;++1)
pProbabilities[flag][i]=1;///第一个骰子,和为1~6的可能都为1
for(int k=2;k<=number;k++)
{
for(int i=0;i<k;i++)
pProbabilities[1-flag][i]=0;//新进来一个骰子,比如现在有两个骰子,则和不可能是1
for(int i=k;i<=6*k;++i)
{
pProbabilities[1-flag][i]=0;
for(int j=1;j<=i&&j<=6;++j)///和为i的次数,等于上一轮和为i-1,i-2...i-6次数的和
pProbabilities[1-flag][i]=pProbabilities[flag][i-j];
}
flag=1-flag;
}
double total=pow((double)6,number);
for(int i=number;i<=6*number;i++)
{
double ratio=(double)pProbabilities[flag][i]/total;
}
delete[] pProbabilities;
delete[] pProbablities;
}
2.扑克牌中的顺子
步骤一:首先将数组排序
步骤二:统计数组中0的个数(王)
步骤三:统计排序之后的数组中相邻数字之间的空缺总数
如果总空缺数为0或者等于王的个数,那就是顺子
3.圆圈中最后剩下的数字
思路一:使用一个环形链表,每次从链表中删除第m个结点,这里需要使用标准SLT库里的List数据结构
思路二:
如果只求最后一个报数胜利者的话,我们可以用数学归纳法解决该问题,为了讨 论方便,先把问题稍微改变一下,并不影响原意:
问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人 继续从0开始报数。求胜利者的编号。
我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新 的约瑟夫环(以编号为k=m%n的人开始):
k k+1 k+2 … n-2, n-1, 0, 1, 2, … k-2并且从k开始报0。
现在我们把他们的编号做一下转换:
k --> 0
k+1 --> 1
k+2 --> 2
…
…
k-2 --> n-2
k-1 --> n-1
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解: 例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情 况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x’=(x+k)%n。
令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]。
递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。 因为实际生活中编号总是从1开始,我们输出f[n]+1。
3.股票的最大利润
i个数字时可能获得的最大利润,记录下前i-1个数据的最小值,这样就能算出第i个数字的最大利润
int MaxDiff(const int* numbers,unsigned length)
{
if(numbers==nullptr&&length<2)
return 0;
int min=numbers[0];
int maxdiff=numbers[1]-min;
for(int i=2;i<length;i++)
{
if(numbers[i-1]<min)
min=numbers[i-1];
int curdiff=number[i]-min;
if(curdiff>max)
maxdiff=curdiff;
}
return maxdiff;
}
4.求1+2+3…n
利用构造函数
5.不用加减乘除做加法
使用位操作
步骤一:不考虑进位,对每一位相加,就是进行异或操作
步骤二:计算进位,只有两个数都是1的时候,才会产生进位,进位就是进行与操作,然后向左移一位。
步骤三:把上面两个步骤的结果相加
6.构建乘积数组
将乘积分成两个数组构成,B[i]=C[i]*D[i]
其中C[i]=C[i-1]*A[i-1];D[i]=D[i+1]*A[i+1]
vector<int> multiply(const vector<int>& A)
{
int n=A.size();
vector<int> C(n);
vector<int> D(n);
vector<int> result(n);
C[0]=1;
for(int i=1;i<n;i++)
{
C[i]=C[i-1]*A[i-1];
}
D[n-1]=1;
for(int i=n-2;i>=0;i--)
{
D[i]=D[i+1]*A[i+1];
}
for(int i=0;i<n;i++)
{
result[i]=C[i]*D[i];
}
return result;
}