剑指offer之66

    xiaoxiao2025-07-31  13

    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; }
    最新回复(0)