zoukankan      html  css  js  c++  java
  • 判断一个正整数是否可以由连续正整数求和而来

    58同城面试遇到的问题,判断一个正整数n是否可以由连续正整数求和而来。我没回答上来,面试官给了提示,回来自己想想,觉得有两种方法:

    1. 模拟法:用一个在数轴上的滑动窗(即一个正整数区间),来模拟求解过程。具体来说,如果滑动窗内整数的和小于n,则滑动窗右边界向右移动,如果滑动窗内整数的和大于n,则滑动窗左边界向右移动,如果滑动窗内整数的和等于n,则n可以由滑动窗内的整数求和表示,程序终止。
    2. 数学分析法:可以证明(证明在本文最后),如果n可以表示为:n=(2*m+1)*2k, m, k>=0; 则m>0时,n可以由连续正整数求和而来,m=0时,n不可以由连续正整数求和而来。实际上,正整数中,只有2的各次方不可以由连续正整数求和而来,如n=1,2,4,8,16,32... ;另一方面,只要n含有大于1的奇数因子,都可以由连续正整数求和而来。

    下面是代码:

    View Code
     1 #include <iostream>
     2 using namespace std;
     3 
     4 //模拟法
     5 bool valid(int n){
     6     if(n<=1) return false;
     7     //定义滑动窗的参数,first: 滑动窗左边界,last: 滑动窗右边界,sum: 滑动窗内整数的和
     8     int first, last, sum;
     9     //参数初始化
    10     first=last=sum=1;
    11     do{
    12         //n>sum, 则滑动窗右边界向右移动
    13         if(n>sum)    {
    14             last++;
    15             sum+=last;
    16         }
    17         //n<sum, 则滑动窗左边界向右移动
    18         else if(n<sum) {
    19             sum-=first;
    20             first++;
    21         }
    22         //n==sum, 循环结束,返回true
    23         else
    24             return true;
    25     }
    26     while(first!=last); //如果滑动窗只含一个整数,循环结束,返回false
    27     return false;
    28 }
    29 
    30 //数学分析法
    31 bool valid2(int n){
    32     while(n%2==0) n/=2;
    33     return n>1;
    34 }
    35 
    36 int main()
    37 {
    38     for(int i=1;i<=1000;i++)
    39         if(!valid(i))
    40             cout<<i<<endl;
    41     for(int i=1;i<=1000;i++)
    42         if(!valid2(i))
    43             cout<<i<<endl;
    44     return 0;
    45 }

    程序的运行结果就不贴出来了,有兴趣的话,可以自己试试。下面来证明前面提到的一个结论:如果n可以表示为:n=(2*m+1)*2k, m, k>=0; 则m>0时,n可以由连续正整数求和而来,m=0时,n不可以由连续正整数求和而来。
    证明:假设n可以由正整数区间[k1,k2],k2>k1>0内的整数求和而来,即

    • n=(k1+k2)(k2-k1+1)/2=(2*m+1)*2k, m, k>=0, k2>=k1>0; 即
    • (k1+k2)(k2-k1+1)=(2*m+1)*2k+1

    容易证明,(k1+k2)和(k2-k1+1)奇偶性不一致,即一奇一偶。如果(k1+k2)为奇数,可以有(m=0时,只有)

    • k1+k2=2*m+1;
    • k2-k1+1=2k+1;

    求得k1=m+1-2k;k2=m+2k;同理如果(k2-k1+1)为奇数,可以有m=0时,只有

    • k2-k1+1=2*m+1;
    • k1+k2=2k+1;

    求得k1=2k-m;k2=m+2k;
    看上去可以得到两个区间[2k-m, m+2k]和[m+1-2k, m+2k](实际上m>0时,最后得到的区间可能更多),但是就这两个区间区间而言,不会同时有效。
    来看看最后的结论,m=0时,两个区间都无效,说明此时,n不可以由正整数区间[k1,k2],k2>k1>0内的整数求和而来。
    0<m<2k 时,[2k-m, m+2k]有效;m>=2k 时,[m+1-2k, m+2k]有效。即m>0, n至少可以由一个正整数区间[k1,k2],k2>k1>0内的整数求和而来。
    证明结束!


    最后,不足之处,不吝赐教!

  • 相关阅读:
    (一)linux 系统命令与文件
    python(1)- 初识python
    四、计算机硬件知识整理
    三、计算机硬件历史
    二、网络基础之网络协议
    jmeter while循环使用
    gitlab分支管理
    gitlab基本操作
    JAVA多种向influxDB中插入数据方式
    JAVA类变量和实例变量
  • 原文地址:https://www.cnblogs.com/emituofo/p/2770193.html
Copyright © 2011-2022 走看看