剑指offer之6/6

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;
        
    }

猜你喜欢

转载自blog.csdn.net/weixin_39373577/article/details/90582442